1

问题描述

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

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

问题:

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

1 回答 1

0

在这里PredicateBuilder可以为您创造奇迹。有了PredicateBuilder您可以构建一个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。

于 2013-11-07T22:12:01.807 回答