Entity Framework - ошибка «Невозможно создать постоянное значение типа« тип закрытия »...» - PullRequest
79 голосов
/ 18 мая 2009

Почему я получаю ошибку:

Невозможно создать постоянное значение типа 'Тип закрытия'. Только примитивные типы (например, Int32, String и Guid) поддерживаются в этот контекст.

Когда я пытаюсь перечислить следующий запрос Linq?

IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
   var myList = from person in entities.vSearchPeople
   where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}

Обновление : Если я попытаюсь сделать следующее, просто чтобы попытаться изолировать проблему, я получу ту же ошибку:

where upperSearchList.All(arg => arg == arg) 

Похоже, проблема в методе All, верно? Есть предложения?

Ответы [ 4 ]

68 голосов
/ 19 мая 2009

Похоже, вы пытаетесь сделать эквивалент условия "ГДЕ ... В". Посмотрите Как писать запросы в стиле WHERE IN с использованием LINQ to Entities , чтобы узнать, как выполнить этот тип запроса с LINQ to Entities.

Кроме того, я думаю, что сообщение об ошибке особенно бесполезно в этом случае, потому что .Contains не сопровождается скобками, что заставляет компилятор распознавать весь предикат как лямбда-выражение.

11 голосов
/ 08 декабря 2011

Последние 6 месяцев я боролся с этим ограничением с помощью EF 3.5, и хотя я не самый умный человек в мире, я почти уверен, что могу предложить что-то полезное по этой теме.

SQL, сгенерированный путем выращивания 50-мильного дерева выражений «стиль OR», приведет к плохому плану выполнения запроса. Я имею дело с несколькими миллионами строк, и влияние оказывается существенным.

Есть небольшой взлом, который я обнаружил, чтобы сделать SQL 'in', который помогает, если вы просто ищете группу сущностей по id:

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}

где pkIDColumn - это имя столбца идентификатора первичного ключа вашей таблицы Entity1.

НО ПРОЧИТАЙТЕ!

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

Если бы у меня было больше времени, я бы попытался представить это визуально, но я не просто изучаю это предложение на мгновение: рассмотрим схему с таблицами Person, GovernmentId и GovernmentIdType. Эндрю Тапперт (Персона) имеет две идентификационные карты (GovernmentId), одну из Орегона (GovernmentIdType) и одну из Вашингтона (GovernmentIdType).

Теперь сгенерируйте из него edmx.

Теперь представьте, что вы хотите найти всех людей, имеющих определенное значение идентификатора, скажем, 1234567.

Это может быть достигнуто одним попаданием в базу данных:

dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);

Вы видите здесь подзапрос? Сгенерированный sql будет использовать «соединения» вместо подзапросов, но эффект тот же. В наши дни SQL-сервер в любом случае оптимизирует подзапросы в объединения под покровом, но в любом случае ...

Ключом к этой работе является .Any внутри выражения.

8 голосов
/ 09 мая 2014

Я нашел причину ошибки (я использую Framework 4.5). Проблема в том, что EF сложного типа, который передается в параметре «Contains», не может быть преобразован в запрос SQL. EF может использовать в запросе SQL только простые типы, такие как int, string ...

this.GetAll().Where(p => !assignedFunctions.Contains(p))

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

Если я могу извлечь из своего списка параметры, которые подходят для моего поиска, я могу использовать:

var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))

Теперь EF больше не работает со сложным типом «Функция», но, например, с простым типом (long). И это прекрасно работает!

0 голосов
/ 02 июля 2013

Я получил это сообщение об ошибке, когда мой объект массива, используемый в функции .All, имеет значение null После того, как я инициализировал объект массива (upperSearchList в вашем случае), ошибка исчезла В этом случае сообщение об ошибке вводило в заблуждение

где upperSearchList.All (arg => person.someproperty.StartsWith (arg)))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...