Using Function logic in LINQ Query net core 3

橙三吉。 提交于 2021-01-27 20:08:00

问题


I have the following enum:

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

and a class

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

and an extension method:

    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;
        }
      }
    }

and SQL Linq query

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

This is a simplified version of my problem. This query used to work, but it is not working any more after the code was converted from net core 2.1 to 3.1. The error msg is The query could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(). I don't want to change it to

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

Because actual function is very complex. I searched it seems LINQ Expression Func can be used, but I haven't figured that yet. What is the best way to do this?


回答1:


IsHighValueWork is just a simple C# method. There is no way to convert that function to SQL by EF.

It is really explained well in that link, why it was working in .net core 2.1. It seems that, in previous versions when EF Core couldn't convert an expression that was part of a query to either SQL or a parameter, it automatically evaluated the expression on the client.

And it is really bad. Because, as noted:

For example, a condition in a Where() call which can't be translated can cause all rows from the table to be transferred from the database server, and the filter to be applied on the client.

So, it seems previously you were just loading all data to the client and then applying filter on the client side.

So, the problem with your code is, that Func cant be translated into Sql. Either fetch all data into app explicitly and filter then or use second version of you code.

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

But, I don't recommend to use that version. It is better to use second version like so:

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

And then:

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


来源:https://stackoverflow.com/questions/59760914/using-function-logic-in-linq-query-net-core-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!