Использование функции logi c в LINQ Query net core 3 - PullRequest
2 голосов
/ 16 января 2020

У меня есть следующее перечисление:

      public enum WorkType
      {
        Type1,
        Type2,
        Type3,
        Type4,
        Type5,
        Type6
       }

и класс

      public class Work {
        public WorkType Type {get; set;}
        ....
      }

и метод расширения:

    public static partial class WorkTypeExtensions
    {
      public static bool IsHighValueWork(this WorkType value)
      {
        switch (value)
        {
            case WorkType.Type1:
            case WorkType.Type2:
                return true;

            default:
                return false;
        }
      }
    }

и SQL запрос Linq

  public List<Work> GetHighValueWork()
  {
    var query = Context.Work.Where( w => w.IsHighValueWork());
    return query.ToList();
   }

Это упрощенная версия моей проблемы. Этот запрос работал, но он больше не работает после преобразования кода из net core 2.1 в 3.1. Сообщение об ошибке: запрос не может быть переведен. Либо переписайте запрос в форме, которую можно перевести, либо явным образом переключитесь на оценку клиента, вставив вызов либо в AsEnumerable (), AsAsyncEnumerable (). Я не хочу менять его на

 public List<Work> GetHighValueWork()
  {
    var query = Context.Work.Where( w => w.Type == WorkType.Type1 || w.Type == WorkType.Type2);
    return query.ToList();
   }

, потому что фактическая функция очень сложна. Я искал, кажется, можно использовать LINQ Expression Fun c, но я еще не понял этого. Каков наилучший способ сделать это?

1 Ответ

4 голосов
/ 16 января 2020

IsHighValueWork - это простой C# метод. Невозможно преобразовать эту функцию в SQL с помощью EF.

Это действительно хорошо объяснено в этой ссылке , почему она работает. net ядро ​​2.1. Похоже, что в предыдущих версиях, когда EF Core не мог преобразовать выражение, которое было частью запроса, либо в SQL, либо в параметр, он автоматически вычислял выражение на клиенте.

И это действительно плохо. Потому что, как было отмечено:

Например, условие в вызове Where (), которое не может быть переведено, может привести к тому, что все строки таблицы будут перенесены с сервера базы данных, а фильтр - в быть примененным к клиенту.

Итак, ранее вы просто загружали все данные на клиент, а затем применяли фильтр на стороне клиента.

Итак, проблема с вашим код, который Func не может быть переведен в Sql. Либо извлекайте все данные в приложение явным образом и затем фильтруйте, либо используйте вторую версию вашего кода.

Context.Work.ToList()
       .Where( w => w.Type.IsHighValueWork());

Но я не рекомендую использовать эту версию. Лучше использовать вторую версию примерно так:

Func<Work, bool> IsHighValueWork = (work) =>
            work.Type == WorkType.Type1 || work.Type == WorkType.Type2;

А потом:

var query = Context.Work.Where(IsHighValueWork);
...