Измените вторую функцию следующим образом:
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 для 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в SQL набор инструкций, которые более не являются понятными, которые имеют дело с таинственными классами, которые не имеют встроенного сопоставления с каким-либо конкретным типом сущности.
Эта проблема фундаментальна для концепции O / RОтображение и отложенное выполнение запроса. A Проекция - это односторонняя операция .После того, как вы спроецируете проект, вы больше не сможете вернуться к обработчику запросов и сказать о, кстати, вот еще несколько условий для вас .Слишком поздно.Лучшее, что вы можете сделать, это взять то, что вам уже дали, и самостоятельно оценить дополнительные условия.
И последнее, но не менее важное, я оставлю вас с обходным путем.Если only то, что вы хотите сделать из своего отображения, это 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, в SQL. Модель домена - это ваш публичный интерфейс . Запросы, которые вы пишете, являются аспектом вашей частной реализации . Важно понимать разницу и поддерживать хорошее разделение интересов.