Преобразование IQueryable из & lt; T & gt; To & lt; TDto & gt; [Дубликат]

Вот что я сделал для частичных совпадений строк. Если у кого-то есть более эффективный способ сделать это, пожалуйста, дайте мне знать.

def stringSearchColumn_DataFrame(df, colName, regex):
    newdf = DataFrame()
    for idx, record in df[colName].iteritems():

        if re.search(regex, record):
            newdf = concat([df[df[colName] == record], newdf], ignore_index=True)

    return newdf
20
задан Aaronaught 6 February 2010 в 16:30
поделиться

2 ответа

Измените вторую функцию следующим образом:

public IEnumerable<DO_RoleInfo> SelectAll()
{
    Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
    return from role in _ctx.DB_RoleInfo.ToList()
           select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}

AutoMapper отлично работает с Linq to SQL, но не может быть выполнен как часть отложенного запроса. Добавление ToList() в конце вашего запроса Linq приводит к немедленной оценке результатов, вместо того, чтобы пытаться перевести сегмент AutoMapper как часть запроса.


Уточнение

Понятие отложенного исполнения (не «ленивая загрузка») не имеет никакого смысла, как только вы изменили полученный тип на то, что не является объектом данных. Рассмотрим эти два класса:

public class DB_RoleInfo
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class DO_RoleInfo
{
    public Role Role { get; set; }    // Enumeration type
}

Теперь рассмотрим следующее отображение:

Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>
    .ForMember(dest => dest.Role, opt => opt.MapFrom(src =>
        (Role)Enum.Parse(typeof(Role), src.Name)));

Это сопоставление полностью прекрасное (если только я не сделал опечатку), но предположим, что вы пишете SelectAll в вашем исходном сообщении, а не в моем пересмотренном:

public IQueryable<DO_RoleInfo> SelectAll()
{
    Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
    return from role in _ctx.DB_RoleInfo
           select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}

Это действительно работает, но, называя себя «запросом», он лежит. Что произойдет, если я попытаюсь написать это против него:

public IEnumerable<DO_RoleInfo> SelectSome()
{
    return from ri in SelectAll()
           where (ri.Role == Role.Administrator) ||
                 (ri.Role == Role.Executive)
           select ri;
}

Подумайте об этом очень сложно. Как Linq to SQL возможно сможет успешно превратить ваш where в настоящий запрос к базе данных?

Linq ничего не знает о классе DO_RoleInfo. Он не знает, как сделать отображение назад - в некоторых случаях это возможно даже не возможно. Конечно, вы можете посмотреть на этот код и пойти «О, это просто, просто найдите« Администратор »или« Исполнительный »в столбце Name« , но вы единственный, кто знает что. Что касается Linq to SQL, запрос является чистым вздором.

Представьте, что кто-то дал вам следующие инструкции:

Перейти в супермаркет и вернуть ингредиенты для сделав Morton Thompson Turkey.

Если вы не сделали этого раньше, и большинство людей этого не сделали, ваш ответ на эту инструкцию, скорее всего, будет:

  • Что, черт возьми, это?

Вы можете пойти на рынок, и вы можете получить конкретные ингредиенты по имени, но вы не можете оценить состояние, которое я вам дал , пока вы там . Я должен сначала «отменить» критерии. Я должен сказать вам, вот ингредиенты, которые нам нужны для этого рецепта - теперь идите и получите их.


Подводя итог, это не простой несовместимость между Linq to SQL и AutoMapper. Это не уникально ни для одной из этих двух библиотек. Не имеет значения , как вы действительно выполняете сопоставление с типом не-сущности - вы могли бы так же легко сделать сопоставление вручную, и вы все равно получите ту же ошибку, потому что теперь вы даете Linq to SQL - набор инструкций, которые уже не понятны, касаются таинственных классов, которые не имеют внутреннего сопоставления с каким-либо конкретным типом объекта.

Эта проблема имеет основополагающее значение для концепции отображения O / R и отложенное выполнение запроса. Проекция - это односторонняя операция. После того, как вы выполните проект, вы больше не сможете вернуться к движку запроса и сказать , кстати, вот еще несколько условий для вас . Слишком поздно. Лучшее, что вы можете сделать, это взять то, что уже вам дали, и оценить дополнительные условия самостоятельно.


И последнее, но не менее важное: я оставлю вас обходным путем. Если единственное, что вы хотите сделать из своего сопоставления, это filter строки, вы можете записать это:

public IEnumerable<DO_RoleInfo> SelectRoles(Func<DB_RoleInfo, bool> selector)
{
    Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
    return _ctx.DB_RoleInfo
        .Where(selector)
        .Select(dbr => Mapper.Map<DB_RoleInfo, DO_RoleInfo>(dbr));
}

Это метод утилиты, который обрабатывает отображение для вас и принимает фильтр на объекте оригинала , а не отображаемый объект. Это может быть полезно, если у вас есть много разных фильтров, но всегда нужно делать одно и то же сопоставление.

Лично я считаю, что вам будет лучше просто написать ответы правильно, сначала определив, что вам нужно для получения из базы данных, затем выполнения любых проекций / отображений, а затем, наконец, если вам нужно выполнить дальнейшую фильтрацию (которой вы не должны), , тогда материализуют результаты с ToList() или ToArray() и записывают больше условий в отношении локального списка.

Не пытайтесь использовать AutoMapper или любой другой инструмент, чтобы скрыть реальные объекты, открытые Linq to SQL. Модель домена - это ваш открытый интерфейс. Запросы, которые вы пишете, являются аспектом вашей частной реализации. Важно понимать разницу и поддерживать хорошее разделение проблем.

23
ответ дан Aaronaught 22 August 2018 в 01:10
поделиться
  • 1
    Спасибо за ваш ответ! Но так, как вы дали, SelectAll будет извлекать все записи из БД. Я хотел бы воспользоваться преимуществами ленивой загрузки. Это означает, что приложение выберет одну запись из БД в SelectByKey, но не все записи в SelectAll. – Sam Zhou 6 February 2010 в 08:42
  • 2
    Ответ Гирта Арнольда ниже - это решение. Для справки, вот соответствующий API github.com/AutoMapper/AutoMapper/blob/master/src/AutoMapper/… – Doguhan Uluca 8 February 2013 в 03:06

Хотя ответ @ Aaronaught был правильным на момент написания, так как часто мир менялся и AutoMapper с ним. В то же время в базу кода были добавлены QueryableExtensions , которые добавили поддержку прогнозов, которые переводились в выражения и, наконец, SQL.

Основной метод расширения ProjectTo 1. Вот как выглядит ваш код:

using AutoMapper.QueryableExtensions;

public IQueryable<DO_RoleInfo> SelectAll()
{
    Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
    return _ctx.DB_RoleInfo.ProjectTo<DO_RoleInfo>();
}

, и он будет вести себя как ручное сопоставление. (Инструкция CreateMap здесь для демонстрационных целей. Обычно вы определяете сопоставления один раз при запуске приложения).

Таким образом, запрашиваются только столбцы, необходимые для сопоставления, и результат IQueryable, у которого все еще есть исходный поставщик запросов (linq-to-sql, linq-to-entities, независимо). Таким образом, он по-прежнему может быть скомпонован, и это будет переведен в предложение WHERE в SQL:

SelectAll().Where(x => x.Id == Key).SingleOrDefault();

1 Project().To<T>() до v. 4.1.0

57
ответ дан Gert Arnold 22 August 2018 в 01:10
поделиться
  • 1
    Этот ответ должен стать новым ответом. – Doguhan Uluca 8 February 2013 в 03:07
  • 2
    Просто добавьте использование AutoMapper.QueryableExtensions; – Colin 22 March 2013 в 16:40
  • 3
    Я получаю следующую ошибку: «Метод« Где »не может следовать методу« Выбрать »или не поддерживается». См. Здесь вопрос ( stackoverflow.com/q/16174351/1133338 ). – Joao Leme 23 April 2013 в 18:01
  • 4
    Обратите внимание, что вы захотите переместить Mapper.CreateMap из этого метода для производственного кода. CreateMap следует вызывать только один раз при запуске приложения, поэтому перемещение всех ваших CreateMaps на какой-то загрузочный / вызов из Application_Start в global.asax - это путь. – Paul Hiles 23 April 2013 в 19:09
  • 5
    последняя строка может быть: SelectAll().SingleOrDefault(x => x.Id == Key); – user1713059 7 May 2015 в 15:03
Другие вопросы по тегам:

Похожие вопросы: