对EntityFramework查询和内存中评估使用相同的表达式

时间:2013-11-07 13:08:31

标签: c# entity-framework lambda

问题描述

在我的应用程序中,我有一个搜索功能,可以根据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参数),我需要构建表达式并每次编译它们,这使得它成为一种非常低效的方式(我想,如果我错了,请纠正我)。

    < / LI>
  • 我可以使用IQueriable将我的单个实体包装在new [] { myEntity }.AsQueriable()中,然后对其进行评估。不确定这会有多好。

问题:

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

1 个答案:

答案 0 :(得分:0)

这里PredicateBuilder可以为你创造奇迹。使用PredicateBuilder,您可以构建一个可以用于Expression的{​​{1}},但在编译时也可以用于对象。

您可以拥有一个构建并返回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); 电话。如果没有它,EF将失败,因为在引擎盖Expand将被调用,无法转换为SQL。 Invoke替换这些调用,以便EF可以将表达式转换为SQL。