【发布时间】:2013-04-29 17:30:18
【问题描述】:
我编写了这个过滤器来只从数据库中获取与特定时间段匹配的文档:
Period 实体很简单,包含两个属性: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));
如您所料,我必须动态构建此过滤器,因为构建过滤器的提交周期的数量可能会有所不同。
(以下是我用来组合lambdas的@987654322@(每个时间段都已提交构建过滤器)
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);
}
这里是我为每个要添加到文档过滤器的期间的每个 lambda 组合:
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();
...我查看了生成的 SQL,没有向 SELECT 语句添加任何内容。
如果我执行查询而不像这样编译生成的表达式:
var query = this.ObjectSet.Where(resultExpression);
我得到了这个例外:
LINQ 不支持 LINQ 表达式节点类型“Invoke” 实体。
这意味着 Linq-To-Entities 查询提供程序不知道如何将我的过滤器转换为 SQL 代码。
现在困扰我的是,从属于我的 Entity 架构的实体(Document 和 Period)进行如此简单的 DateTime 比较如何会弄乱提供者?
有什么想法可以实现这样的过滤吗?
【问题讨论】:
-
你试过
this.ObjectSet.Where(resultExpression)吗? -
@svick :如果我不编译 resultExpression,我会收到以下异常:LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。
-
@JoanLeaven 这意味着您实际上是第一次使用查询提供程序,而不仅仅是在 linq 中对对象执行全部操作。现在您需要弄清楚如何创建查询提供者知道如何翻译的查询。
-
@JoanLeaven 不是它不知道如何翻译的单个条件表达式,而是你将它们组合起来的方法是创建一个它不知道如何解析的复杂结构。
-
@Servy :这是我发现动态组合我的谓词的唯一方法。你知道更简单或更好的方法吗?
标签: c# linq-to-entities linq-expressions