在我的应用程序中,我有一个搜索功能,可以根据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
参数),我需要构建表达式并每次编译它们,这使得它成为一种非常低效的方式(我想,如果我错了,请纠正我)。
我可以使用IQueriable
将我的单个实体包装在new [] { myEntity }.AsQueriable()
中,然后对其进行评估。不确定这会有多好。
答案 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。