【发布时间】:2011-08-04 03:22:38
【问题描述】:
我使用的是 Entity Framework 4.1 Code First。在我的实体中,我有三个日期/时间属性:
public class MyEntity
{
[Key]
public Id { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
[NotMapped]
public DateTime? QueryDate { get; set; }
// and some other fields, of course
}
在数据库中,我总是填写从/到日期。我使用一个简单的 where 子句查询它们。但在结果集中,我想包含我查询的日期。我需要坚持这一点,以使其他一些业务逻辑正常工作。
我正在研究一种扩展方法来做到这一点,但我遇到了问题:
public static IQueryable<T> WhereDateInRange<T>(this IQueryable<T> queryable, DateTime queryDate) where T : MyEntity
{
// this part works fine
var newQueryable = queryable.Where(e => e.FromDate <= queryDate &&
e.ToDate >= queryDate);
// in theory, this is what I want to do
newQueryable = newQueryable.Select(e =>
{
e.QueryDate = queryDate;
return e;
});
return newQueryable;
}
这不起作用。如果我使用 IEnumerable,它可以工作,但我想将其保留为 IQueryable,以便一切都在数据库端运行,并且这种扩展方法仍然可以用于另一个查询的任何部分。当它是 IQueryable 时,我收到以下编译错误:
带有语句体的 lambda 表达式不能转换为表达式树
如果这是 SQL,我会这样做:
SELECT *, @QueryDate as QueryDate
FROM MyEntities
WHERE @QueryDate BETWEEN FromDate AND ToDate
所以问题是,我怎样才能转换我已经必须包含这个额外属性分配的表达式树?我研究了 IQueryable.Expression 和 IQueryable.Provider.CreateQuery - 那里有一个解决方案。也许可以将赋值表达式附加到现有的表达式树?我对表达式树方法不够熟悉,无法弄清楚这一点。有什么想法吗?
示例用法
澄清一下,目标是能够执行如下操作:
var entity = dataContext.Set<MyEntity>()
.WhereDateInRange(DateTime.Now)
.FirstOrDefault();
并且将 DateTime.Now 保留到结果行的 QueryDate 中,而不会从数据库查询返回多于一行。 (使用 IEnumerable 解决方案,在 FirstOrDefault 选择我们想要的行之前返回多行。)
另一个想法
我可以继续将 QueryDate 映射为真实字段,并将其 DatabaseGeneratedOption 设置为 Computed。但是我需要一些方法将“@QueryDate as QueryDate”注入到由 EF 的 select 语句创建的 SQL 中。由于它是计算出来的,EF 不会在更新或插入期间尝试提供值。那么如何才能将自定义 SQL 注入到 select 语句中呢?
【问题讨论】:
标签: linq entity-framework entity expression-trees iqueryable