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)))