«Тип узла выражения LINQ« Invoke »не поддерживается в LINQ to Entities», когда лямбда-выражение передается в качестве параметра, но не при непосредственном использовании - PullRequest
0 голосов
/ 14 октября 2018

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

У меня есть запрос Linq следующим образом ...

List<int> ids = ctx
  .Where(a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))
  .Select(a => a.SystemID)
  .Distinct()
  .ToList();

... где pitID является int, а vals является List<int>

Это прекрасно работает, но так как у меня есть четыре таких запроса, отличающихся только лямбда-выражением в предложении Where, я подумал, что было бы лучше вытащить код в общий метод ...

private List<int> DoAdvancedSearch(Func<MyType, bool> p)
{
  return ctx
    .Where(a => p(a))
    .Select(a => a.SystemID)
    .Distinct()
    .ToList();
}

Затем я мог бы вызвать это следующим образом ...

List<int> ids = DoAdvancedSearch(systemIDs,
                 a => a.PartInformationTypeID == pitID && vals.Contains(a.PartDefinitionID))

Однако этот метод выдает исключение времени выполнения " System.NotSupportedException: 'Выражение LINQТип узла 'Invoke' не поддерживается в LINQ to Entities. ' "

Прочитав множество других вопросов с тем же исключением, мне удалось решить его, изменив метод следующим образом ...

private List<int> DoAdvancedSearch(Expression<Func<MyType, bool>> p)
{
  return ctx
    .Where(p)
    .Select(a => a.SystemID)
    .Distinct()
    .ToList();
}

Однако я не могу найти одну вещь: почему мой первый запрос?ove (с лямбдой в предложении Where) не сработало, тогда как второй запрос в извлеченном методе сработал?Я не думаю, что это проблема с реальной лямбдой, так как она не содержит ничего, что EF не может перевести на SQL (что он явно делает с первой версией), так что, очевидно, это связано с тем, чтоЛямбда была передана как Func, а не Expression.

Наиболее близким к объяснению я нашел ответ на на этот вопрос , но это основывалось на том факте, чтопередаваемый код не может быть переведен в SQL.Как я уже сказал, я не думаю, что в этом проблема, так как EF удалось хорошо перевести ее в первом фрагменте кода.

Любой, кто сможет объяснить , почему мой пример не работаетс Func?

В качестве дополнительного вопроса любой, кто сможет объяснить, почему .Where(a => p(a)) выдал ошибку компилятора " Ожидается имя метода " на p, но с.Where(p)?Я думал, что они были эквивалентны.

Спасибо

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

Если вы передадите Experssion<Func<MyType, bool>>, это может сработать.Func является ссылкой на скомпилированный метод .net.Expression<Func - это дерево выражений с той же сигнатурой вызова, что и у функции.

0 голосов
/ 14 октября 2018

Объект Expression компилируется в структуру данных (дерево выражений).Это преобразуется в код SQL во время выполнения EF.Func, с другой стороны, преобразуется компилятором в исполняемый код IL.Когда вы просите EF перевести запрос, содержащий Where (x => f (x)), у вас есть Func f, который является IL-кодом, и небольшое дерево выражений вокруг него, описывающее вызов функции, представленной f.Сообщение об ошибке говорит о том, что это дерево выражений «Invoke» не может быть преобразовано в SQL, что является разумным, поскольку то, что вызывается, является частью кода IL.

Обратите внимание, что в вашем первом примере, где WhereВызов является встроенным, вы используете выражение, а не Func.Это связано с тем, что лямбда-выражения в C # могут иметь оба типа, а при использовании метода расширения Where в IQueryable параметр имеет тип Expression, поэтому вся лямбда-выражение компилируется в дерево выражений.

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