如何分配IQueryable <T>的属性值?

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语句呢?

Mat*_*int 0

感谢您提供的所有宝贵反馈。听起来答案是“不——你不能那样做”。

所以 - 我想出了一个解决方法。这对于我的实现来说非常具体,但它确实有效。

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 解决方案,但它通过将其从该世界中删除来实现相同的效果。