我已编写此过滤器以仅获取与数据库中某些时间段匹配的文档:
期间实体很简单,包含两个属性: DateFrom 和 DateTo 。
我需要从lambdas构建一个过滤器,每个 Period 用于构建过滤器。
过滤器完全构建后,必须如下所示:
ObjectSet.Where(d =>
(d.Date >= Period1.DateFrom && d.Date <= Period1.DateTo)
|| (d.Date >= Period2.DateFrom && d.Date <= Period2.DateTo)
|| (d.Date >= Period3.DateFrom && d.Date <= Period3.DateTo));
您可以猜测,我必须动态构建此过滤器,因为用于构建过滤器的提交的期间的数量可能会有所不同。 < / p>
(以下是 在这里,我将每个lambda组合在一起,以便添加到文档过滤器: 问题是,当我启动查询的延迟执行时...... ...我查看生成的SQL,没有添加任何内容到SELECT语句。 如果我执行查询而不编译生成的表达式,如下所示: 我得到了这个例外: LINQ to不支持LINQ表达式节点类型'Invoke'
实体。 这意味着Linq-To-Entities查询提供程序不知道如何将我的过滤器转换为SQL代码。 现在困扰我的是如何将实体(文档和期间)中的这种简单的DateTime比较作为我的实体架构的一部分会让提供商陷入困境? 我有什么想法可以实现这样的过滤?Expression
我用来组合lambdas(每个时间段都已提交以构建过滤器) private Expression<Func<T, bool>> CombineWithOr<T>(
Expression<Func<T, bool>> firstExpression,
Expression<Func<T, bool>> secondExpression)
{
var parameter = Expression.Parameter(typeof(T), "x");
var resultBody = Expression.Or(
Expression.Invoke(firstExpression, parameter),
Expression.Invoke(secondExpression, parameter));
return Expression.Lambda<Func<T, bool>>(resultBody, parameter);
}
public IList<Document> GetDocuments(IList<Periods> periods)
{
Expression<Func<Document, bool>> resultExpression = n => false;
foreach (var submittedPeriod in periods)
{
var period = submittedPeriod;
Expression<Func<Document, bool>> expression =
d => (d.Date >= period.DateFrom && d.Date <= period.DateTo);
resultExpression = this.CombineWithOr(resultExpression, expression);
}
var query = this.ObjectSet.Where(resultExpression.Compile());
}
var documents = query.ToList();
var query = this.ObjectSet.Where(resultExpression);
答案 0 :(得分:0)
在查询之前尝试.AsExpandable()
。更多信息是here
答案 1 :(得分:0)
问题出在你的组合功能上。 SQL to Entities并不真正喜欢Invoke。这是一个对我有用的组合功能:
public static class ExpressionCombiner
{
public static Expression<Func<T, bool>> Or<T>(Expression<Func<T, bool>> a, Expression<Func<T, bool>> b)
{
var parameter = Expression.Parameter(typeof(T), "x");
var substituter = new SubstituteParameter(parameter, p => true);
var resultBody = Expression.Or(
substituter.Visit(a.Body),
substituter.Visit(b.Body));
Expression<Func<T, bool>> combined = Expression.Lambda<Func<T, bool>>(resultBody, parameter);
return combined;
}
}
public class SubstituteParameter : ExpressionVisitor
{
private ParameterExpression toReplace;
private Func<ParameterExpression, bool> isReplacementRequiredFunc;
public SubstituteParameter(ParameterExpression toReplace, Func<ParameterExpression, bool> isReplacementRequiredFunc)
{
this.toReplace = toReplace;
this.isReplacementRequiredFunc = isReplacementRequiredFunc;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return isReplacementRequiredFunc(node) ? toReplace : node;
}
}