【问题标题】:Using the same expression for EntityFramework queries and in-memory evaluation对 EntityFramework 查询和内存评估使用相同的表达式
【发布时间】:2013-11-07 13:08:30
【问题描述】:

问题描述

在我的应用程序中,我有一个搜索功能,它基于 EntityFramework DbSet 对象之上的用户输入构建一个复杂的搜索查询,并针对数据库运行它,如下所示:

public static IQueryable<MyEntity> ApplySearchQuery(SearchSpec search, IQueryable<MyEntity> query)
{
    if (search.Condition1.HasValue)
        query = query.Where(e => e.SomeProperty == search.Condition1);
    if (search.Condition2.HasValue)
        query = query.Where(e => e.OtherProperty == search.Condition2);
    ....
}

这在数据库方面表现得很好。现在我发现我手头只有一个MyEntity,我想看看一个特定的SearchSpec 是否与实体匹配。而且我需要为可能大量的SearchSpec 对象执行此操作,因此性能很重要。

我也很想避免重复表达。

这是我目前的想法:

  • 我可以在表达式上调用 Expression.Compile() 以将它们转换为委托,然后调用它们。但是由于我有一个参数(search 参数),我需要构建表达式并每次都编译它们,这是一种非常低效的方式(我想,如果我错了,请纠正我)。

  • 我可以使用new [] { myEntity }.AsQueriable() 将我的单个实体包装在IQueriable 中,然后评估其上的查询。不确定这会表现如何。

问题:

  • 以上哪种方法更快?
  • 我的任何假设(关于限制)是否错误?
  • 还有其他我没有想到的方法吗?

【问题讨论】:

  • 这种方法 - new [] { myEntity }.AsQueriable() - 对我来说似乎没问题。至少,将单个 myEntity 从数组转换为 IQueryable&lt;MyEntity&gt; 不会对性能造成重大影响。
  • @Dennis 是的,这是真的。我担心的是底层可查询的执行方式。例如,如果布尔条件(表达式)被编译然后执行,它并不比第一种方法好。

标签: c# entity-framework lambda


【解决方案1】:

这里PredicateBuilder 可以为您创造奇迹。使用PredicateBuilder,您可以构建一个Expression,该Expression 可以用于IQueryable,但在编译时也可以用于对象。

你可以有一个方法来构建并返回Expression

using LinqKit;

Expression<Func<MyEntity, bool>> CreateExpression(SearchSpec search)
{
    var predicate = PredicateBuilder.True<MyEntity>();

    if (search.Condition1.HasValue)
        predicate = predicate.And(e => e.SomeProperty == search.Condition1);
    if (search.Condition2.HasValue)
        predicate = predicate.And(e => e.OtherProperty == search.Condition2);
    ...
    return predicate;
}

用作:

 var predicate = CreateExpression(search);
 var result = query.Where(predicate.Expand()); // will be translated into SQL.

 var match = predicate.Compile()(myEntity);

注意Expand 电话。没有它,EF 将失败,因为在后台 Invoke 将被调用,它不能被翻译成 SQL。 Expand 替换了这些调用,以便 EF 可以将表达式转换为 SQL。

【讨论】:

  • 这很有趣,非常感谢,我今天学到了新的一课。但是,它应该为每个搜索规范编译,我不能以某种方式缓存编译。 (在内存中匹配时,我有一个实体和数千个搜索规范)
  • 这真的有问题吗?在内存中编译和匹配应该非常快。既然您说它“在数据库方面表现得非常好”,其中执行了许多评估并进行了往返,我不希望对一个对象的内存评估有任何问题。我可以将表达式重组为where !search.Condition1.HasValue || e.SomeProperty == search.Condition1 等链。这将创建一个大表达式,但 whole 表达式将始终发送到数据库(尽管可以重用执行计划)。
猜你喜欢
  • 1970-01-01
  • 2013-02-04
  • 2012-05-08
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多