Mat*_*int 5 linq entity entity-framework iqueryable expression-trees
我正在使用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
}
Run Code Online (Sandbox Code Playgroud)
在数据库中,我总是填充From/To日期.我使用简单的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;
}
Run Code Online (Sandbox Code Playgroud)
这不起作用.它可以工作,如果我使用IEnumerable,但我想保持它为IQueryable所以一切都在数据库端运行,这个扩展方法仍然可以在另一个查询的任何部分使用.当它是IQueryable时,我得到以下的编译错误:
具有语句主体的lambda表达式无法转换为表达式树
如果这是SQL,我会做这样的事情:
SELECT *, @QueryDate as QueryDate
FROM MyEntities
WHERE @QueryDate BETWEEN FromDate AND ToDate
Run Code Online (Sandbox Code Playgroud)
所以问题是,我如何转换我已经拥有的表达式树来包含这个额外的属性赋值?我已经研究过IQueryable.Expression和IQueryable.Provider.CreateQuery - 那里有一个解决方案.也许赋值表达式可以附加到现有的表达式树?我不太熟悉表达式树方法来解决这个问题.有任何想法吗?
示例用法
澄清一下,目标是能够执行以下操作:
var entity = dataContext.Set<MyEntity>()
.WhereDateInRange(DateTime.Now)
.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
并将DateTime.Now持久化到结果行的QueryDate中,而不从数据库查询返回多行.(使用IEnumerable解决方案,在FirstOrDefault选择我们想要的行之前会返回多行.)
另一个想法
我可以继续将QueryDate映射为真实字段,并将其DatabaseGeneratedOption设置为Computed.但是我需要一些方法将"@QueryDate作为QueryDate"注入到EF的select语句创建的SQL中.由于它是计算的,因此EF不会尝试在更新或插入期间提供值.那么我怎样才能将自定义SQL注入select语句呢?
感谢您提供的所有宝贵反馈。听起来答案是“不——你不能那样做”。
所以 - 我想出了一个解决方法。这对于我的实现来说非常具体,但它确实有效。
public class MyEntity
{
private DateTime? _queryDate;
[ThreadStatic]
internal static DateTime TempQueryDate;
[NotMapped]
public DateTime? QueryDate
{
get
{
if (_queryDate == null)
_queryDate = TempQueryDate;
return _queryDate;
}
}
...
}
public static IQueryable<T> WhereDateInRange<T>(this IQueryable<T> queryable, DateTime queryDate) where T : MyEntity
{
MyEntity.TempQueryDate = queryDate;
return queryable.Where(e => e.FromDate <= queryDate && e.ToDate >= queryDate);
}
Run Code Online (Sandbox Code Playgroud)
神奇的是,我使用线程静态字段来缓存查询日期,以便稍后在同一线程中可用。事实上,我在 QueryDate 的 getter 中取回它是特定于我的需求的。
显然,这不是原始问题的 EF 或 LINQ 解决方案,但它通过将其从该世界中删除来实现相同的效果。
| 归档时间: |
|
| 查看次数: |
7415 次 |
| 最近记录: |