我写了一些参数化Lambda查询
//Method 1:
Func<SalesOrderLineEntity, bool> func01 = (o => o.SOLNumber == "123456");
var q01 = _context.SalesOrderLineEntities.Where(func01).ToList();
//Got the result, but SQLServer Read All Records to memory before "where"
//Method 2:
Expression<Func<SalesOrderLineEntity, bool>> exp02 = (o => o.SOLNumber == "123456");
var q02 = _context.SalesOrderLineEntities.Where(exp02).ToList();
//Got the result,Exec "Where" in SQLServer
//Method 3:
Expression<Func<SalesOrderLineEntity, bool>> exp03 = (o => func01(o));
var q03 = _context.SalesOrderLineEntities.Where(exp03.Compile()).ToList();
//Same to Method 1,because Compile() result is Func<SalesOrderLineEntity, bool>
//Method 4:
var q04 = _context.SalesOrderLineEntities.Where(exp03).ToList();
//Error:The LINQ expression node type 'Invoke' is not supported in LINQ to Entities
方法1和3 :效率非常低 方法4 :错误
方法2 :我需要通过Lambda构建表达式。我觉得这很困难,因为我会使用很多“if,else”。更容易创建一个函数。 这样做的正确方法是什么?
答案 0 :(得分:1)
方法1 :EF读取数据库中的所有记录,因为您将Func
传递给Where
子句,这不是正确的候选者:EF无法提取需要从中获取信息来构建查询,它只能在内存集合中使用该函数。
方法2 :这是执行EF查询的正确方法,因为EF会根据Expression tree
构建实际查询。当您编写.Where
时,它可能与方法1相同,但这是不同的。
IQueryable扩展方法正在使用Expression trees,因此您可以(或EF可以)在运行时评估该信息。
方法3 :这与方法1基本相同,因为您编译了表达式。这是使用它们时的一个关键区别:表达式包含构建实际操作的信息,但这不是操作本身。您需要先编译它(或者例如,您可以根据它们构建SQL查询,这就是EF的工作方式)。
方法4 :EF无法将您的func01()
调用转换为任何SQL函数。它无法转换任何类型的代码,因为它需要等效的SQL操作。你可以尝试使用一般方法,你会得到相同的结果,而不是关于Func。
如果我们简化基础流程,那么上面的答案可能会更清楚。
//Method 2:
Expression<Func<SalesOrderLineEntity, bool>> exp02 = (o => o.SOLNumber == "123456");
var q02 = _context.SalesOrderLineEntities.Where(exp02).ToList();
//Got the result,Exec "Where" in SQLServer
EF可以阅读以下内容(通过表达式):
Where
SalesOrderLineEntity
,我有一个该类型的映射SOLNumber
必须等于“123456”SOLNumber
的映射,所以很好当然,您不能使用Func
来执行此操作,例如因为该对象不包含这些信息。
答案 1 :(得分:0)
不确定这是否适用,但是你看一下编译的查询:Compiled Queries (LINQ to Entities)这会导致更高效的SQL语句