Я очень интересуюсь Linq к SQL с Ленивой функцией загрузки. И в моем проекте я использовал AutoMapper для отображения Модели DB на Модель предметной области (от DB_RoleInfo
кому: DO_RoleInfo
). В моем коде репозитория как указано ниже:
public DO_RoleInfo SelectByKey(Guid Key)
{
return SelectAll().Where(x => x.Id == Key).SingleOrDefault();
}
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);
}
SelectAll
метод выполняется хорошо, но когда я звоню SelectByKey
, Я получаю ошибку:
Метод “RealMVC.Data. DO_RoleInfo MapDB_RoleInfo, DO_RoleInfo” не мог перевести в SQL.
Случается так, что Автокартопостроитель не поддерживает Linq полностью?
Вместо Автокартопостроителя я попробовал ручной код отображения ниже:
public IQueryable<DO_RoleInfo> SelectAll()
{
return from role in _ctx.DB_RoleInfo
select new DO_RoleInfo
{
Id = role.id,
name = role.name,
code = role.code
};
}
Этот метод прокладывает себе путь, я хочу его к.
Измените вторую функцию на это:
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
. Он не знает, как выполнить отображение в обратном направлении - в некоторых случаях это даже невозможно. Конечно, вы можете посмотреть на этот код и ввести «О, это просто, просто найдите« Администратор »или« Исполнительный »в столбце Имя
« , но вы » re единственный, кто это знает. Что касается Linq to SQL, запрос - полная чушь.
Представьте, что кто-то дал вам эти инструкции:
Идите в супермаркет и принесите ингредиенты для приготовления индейки Мортона Томпсона.
Если вы не сделали это раньше, а большинство людей этого не сделали, ваш ответ на это указание, скорее всего, будет следующим:
Вы можете пойти на рынок и вы можете получить определенные ингредиенты по названию, но вы не можете оценить состояние, которое я вам поставил , пока вы там . Сначала мне нужно "отключить отображение" критериев .Я должен вам сказать, вот ингредиенты, которые нам нужны для этого рецепта - теперь идите и принесите их.
Подводя итог, это не простая несовместимость между Linq to SQL и AutoMapper. Он не уникален ни для одной из этих двух библиотек. Не имеет значения , как вы на самом деле выполняете сопоставление с типом, не являющимся сущностью - вы можете так же легко выполнить сопоставление вручную, и вы все равно получите ту же ошибку, потому что теперь вы даете Linq в SQL - набор инструкций, которые больше не понятны, касающиеся загадочных классов, которые не имеют внутреннего сопоставления с каким-либо конкретным типом сущности.
Эта проблема фундаментальна для концепции отображения O / R и отложенного выполнения запроса. проекция - это односторонняя операция . После того, как вы спроектируете, вы больше не сможете вернуться к механизму запросов и сказать о, кстати, вот еще несколько условий для вас . Это очень поздно. Лучшее, что вы можете сделать, - это взять то, что он вам уже дал, и самостоятельно оценить дополнительные условия.
И последнее, но не менее важное: я предлагаю вам обходной путь. Если единственная вещь, которую вы хотите сделать из своего сопоставления, - это фильтр строк, вы можете написать следующее:
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. Модель предметной области - это ваш открытый интерфейс . Запросы, которые вы пишете, являются аспектом вашей частной реализации . Важно понимать разницу и четко разделять проблемы.