Entity Framework和编译表达式的性能问题

3
我们正在使用EF进行数据访问,我们有一个像这样的查询:
Expression<TTable, bool> expression = CreateSomeExpression();
var filter = finalExpression.Compile();
var results = db.t_Table.Where(filter).Select(x=>...);

我的问题是,EF是否能够根据已编译的表达式构建正确的查询?
举个例子,如果我的表格是:
t_Table 
( key int,
  value_1 varchar(30),
  value_2 varchar(30)
)

需要编译的表达式是:

p => p.value_1 = 100

这会在EF中翻译成什么:
select * from t_Table where value_1 = 100

或者它会被翻译成

select * from t_Table

在结果上执行linq查询之后,是否有一种方法可以检查EF在数据库上实际调用的SQL查询语句?

非常感谢您提前的帮助。

更新

虽然被接受的答案是100%正确的(因此是被接受的答案),但解决我的问题的方法是简单地删除编译。 删除后,正确的SQL查询具有正确的where clause


3
  1. 尝试一下。
  2. 是的,results.ToString()应该给你SQL。
- Jcl
看一下这些链接。http://stackoverflow.com/a/4703001/1977871 https://dev59.com/P3M_5IYBdhLWcg3wWRyV#1412902 如果你想要生成运行时的linq查询,你应该看看dynamiclinq.azurewebsites.net。它非常灵活。 - VivekDev
@Jcl 感谢您的评论。我已经尝试过它并且它可以工作,但是我更担心的是结果返回的性能影响(例如,我不想要完整的表结果)。results.ToString() 返回:System.Linq.Enumerable+WhereSelectEnumerableIterator2[CLASS_NAME, RESULT_CLASS_NAME]`(其中class_name是表类名,result_classname是select返回类型的类型) - kha
1
如果 ToString() 生成了 System.Linq.Enumerable+WhereSelectEnumerableIterator...,那么这清楚地表明 EF 将在内存中执行查询的一部分。预期输出是一个 SQL 查询字符串 (SELECT ...)。@Kiril Shlenskiy 的答案解释了这一点。只需不要使用 .Compile(),而是使用表达式即可。 - Ivan Stoev
@IvanStoev 很好!成功了。非常感谢你的帮助。移除编译是解决方案。 - kha
1个回答

6

您编译的表达式(得到一个类型为Func<TTable, bool>的委托)实际上导致对表格的完全加载,即

select * from t_Table

......然后将它们加载到内存中后过滤实体。

Entity Framework 只能将 表达式(即 Expression<Func<TTable, bool>>)转换为SQL查询。它不能将已编译的 委托Func<TTable, bool>)拆解成后续可翻译为SQL查询的形式。

这就是重载决策发挥作用的地方。 DbSet<T> 实现了 IQueryable<T>IEnumerable<T> 两个接口。

  • 当您在 IQueryable<T> 上使用扩展方法(大多数都接受表达式参数,即 Where<T>(Expression<Func<T, bool>>))时,您的查询会在DB引擎中执行。

  • 但是一旦您切换到 IEnumerable<T> 扩展方法(如 Where<T>(Func<T, bool>)),EF 就没有选择,只能将整个实体集加载到内存中,然后像任何其他内存集合一样迭代处理结果缓存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接