Entity Framework - "Невозможно создать постоянное значение типа" Closure type "..." error
Почему я получаю ошибку:
Невозможно создать постоянное значение типа 'Closure type'. Только примитивные типы (например, 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)
Итак, похоже, проблема в методе "Все", правильно? Любые предложения?
Ответы
Ответ 1
Похоже, вы пытаетесь сделать эквивалент условия "WHERE... IN". Проверьте Как написать запросы стиля WHERE IN с использованием LINQ to Entities для примера того, как делать этот тип запроса с LINQ to Entities.
Кроме того, я думаю, что сообщение об ошибке особенно бесполезно в этом случае, потому что .Contains
не сопровождается скобками, что заставляет компилятор распознавать весь предикат как выражение лямбда.
Ответ 2
Я провел последние 6 месяцев, борясь с этим ограничением с помощью EF 3.5, и хотя я не самый умный человек в мире, я уверен, что у меня есть что-то полезное в этой теме.
SQL, сгенерированный ростом деревьев высотой 50 миль в выражении "OR style", приведет к плохим планам выполнения запросов. Я имею дело с несколькими миллионами строк, и влияние существенное.
Есть небольшой взлом, который я нашел для 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-сервер в любом случае оптимизирует подзапросы в объединениях под обложками, но в любом случае...
Ключом к этой работе является. внутри внутри выражения.
Ответ 3
Я нашел причину ошибки (я использую 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 больше не имеет сложного типа "Функция", но, например, с простым типом (длинным). И это прекрасно работает!
Ответ 4
Я получил это сообщение об ошибке, когда мой объект массива, используемый в функции .All, равен нулю
После того как я инициализировал объект массива (upperSearchList в вашем случае), ошибка исчезла
В этом случае сообщение об ошибке вводит в заблуждение
где upperSearchList.All(arg = > person.someproperty.StartsWith(arg)))