Метод All должен оценивать аргумент против всех элементов в списке. Он работает нормально в обычном Linq, но когда я пытаюсь использовать его с EF, выдается ошибка (« Невозможно создать постоянное значение типа« Тип закрытия ». В этом случае поддерживаются только примитивные типы (например, Int32, String и Guid)». контекст. ")
Пример:
var myList = from person in entities.People
where searchList.All(arg => arg == arg).ToList();
(arg == arg вот только для иллюстрации моего вопроса)
В моем сценарии searchList - это список, содержащий элементы поиска, такие как «Джон», «Бухгалтерия», «75». В моем EF-запросе я хочу получить все записи в People, которые John, Accounting и 75 появляются в некоторых указанных полях для поиска. Более реалистичным примером будет что-то вроде этого:
where SearchList.All((person.FirstName + " " + person.LastName + " " + person.DepartmentName + " " + person.Phone).Contains)
Второй пример также хорошо работает с Linq в памяти, но EF это не нравится.
Пожалуйста помоги! Что я могу сделать, чтобы это работало?
Это более конкретный вопрос, полученный из другого моего вопроса .
IEnumerable<string> searchList = ParseSearchText(searchText); //search text is broken into search tokens - each token is an element in searchList. For instance "John", "Sales", "654"
var peopleQuery = from person in entities.vSearchPeople
where upperSearchList.All((person.FirstName + " " + person.Lastname + " " + person.Phone).ToUpperInvariant().Contains)
select person;
Entity Framework поддерживает не все запросы. Это становится очевидным, если вы думаете о чем-то вроде следующего
dataContext.Persons.Where(person => MyMethod(person));
с MyMethod()
возвращающим логическое значение. Метод может делать все, и вы не можете перевести все на SQL. Решение состоит в том, чтобы получить все объекты в локальную память с помощью ToList()
а затем использовать LINQ to Object.
dataContext.Persons.ToList().Where(person => MyMethod(person));
От вашего фактического запроса зависит, можно ли его переписать, чтобы он мог быть преобразован в SQL с помощью Entity Framework или если вы должны выполнить запрос в локальной памяти, используя LINQ to Object.
Исключение, которое вы упомянули, звучит так, будто вы пытаетесь сделать что-то вроде следующего.
Company company = datacontext.Companies.Where(company.Name == "ACME").Single();
dataContext.Employees.Where(employee => employee.Company == company);
LINQ to Entity не поддерживает выражения, содержащие сущности, поэтому сравнение сущностей Company
недопустимо. В этом случае вы можете переписать его следующим образом.
dataContext.Employees.Where(employee => employee.Company.Id == company.Id);
Это сравнивает только идентификаторы - примитивный тип, такой как целое число или GUID - и это может быть преобразовано в SQL.
Пример поиска слово за словом (см. Также комментарии)
IQueryable<People> result = entities.People;
foreach (String item in searchList)
{
// This copy is important in order not to modify the closure.
String itemCopy = item;
result = result.Where(p =>
p.FirstName.ToUpper().Contains(itemCopy) ||
p.LastName.ToUpper().Contains(itemCopy) ||
p.Phone.ToUpper().Contains(itemCopy));
}
Это создаст запрос слово за словом. Отметил, что Entity Framework распознает ToUpper()
, ToLower()
и Contains()
(и некоторые другие) - поэтому я был строг, когда сказал, что Entity Framework не распознает вызовы методов. Это делает, но не много и не ToUpperInvariant()
и ToLowerInvariant()
. Кроме того , этот запрос переводится в CHARINDEX()
вызовы функций , используя параметры сортировки столбца, следовательно , поиск может быть чувствителен к регистру без явного ToUpper()
или ToLower()
вызовы.
Это хороший пример того, что хорошо работает в методе All ().
model.ReferenceList = db.JournalCardReference.OrderBy(a => a.orderF)
.Include(x => x.JournalCardField)
.Where(x => x.JournalCardField
.All(f => f.deleted == null || f.deleted != true)).ToList();