Entity Framework - метод "Все"

entity-framework linq linq-to-entities

Вопрос

Метод 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();


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow