问题
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