将派生属性包含到linq到实体查询中

本文关键字:实体 查询 linq 属性 包含 派生 | 更新日期: 2023-09-27 18:25:07

下面是一个基于名为Task:的Poco类的简单项目

class Program
{
    static void Main(string[] args)
    {
        using (MyDbContext ctx = new MyDbContext())
        {
            // first query
            DateTime compareDate = DateTime.Now + TimeSpan.FromDays(3);
            var res = ctx.Tasks.Where(t => t.LastUpdate < compareDate).ToList();
            // second query
            res = ctx.Tasks.Where(t => t.ShouldUpdate).ToList();
        }
    }
}
public class MyDbContext : DbContext
{
    public DbSet<Task> Tasks { get; set; }
}
public class Task
{
    public int ID { get; set; }
    public DateTime LastUpdate { get; set; }
    public  bool ShouldUpdate
    {
        get
        {
            return LastUpdate < DateTime.Now + TimeSpan.FromDays(3);
        }
    }
}

我想做的是查询上下文dbset,在where子句中包括ShouldUpdate派生的属性。

"第一个查询运行良好"(我不能在一行中写它,但这无关紧要)。

如您所知,我们在"第二个查询"上得到一个NotSupportedException,并显示以下消息:LINQ to Entities中不支持指定的类型成员"ShouldUpdate"。仅支持初始值设定项、实体成员和实体导航属性。

没错,我可以理解为什么会发生这种情况,但我需要将派生的信息封装在Task对象中,这样我就可以在网格中显示属性或在其他地方使用它,而不会复制其背后的逻辑。

有没有一种聪明的技术可以做到这一点?

注意:ShouldUplate物业的技术名称是什么?派生?计算计算?

将派生属性包含到linq到实体查询中

我终于找到了解决方案。。您可以将部分查询(表达式)存储在静态文件中,并像这样使用它们:

class Program
{
    static void Main(string[] args)
    {
        using (MyDbContext ctx = new MyDbContext())
        {
            res = ctx.Tasks.Where(Task.ShouldUpdateExpression).ToList();
        }
    }
}
public class MyDbContext : DbContext
{
    public DbSet<Task> Tasks { get; set; }
}
public class Task
{
    public int ID { get; set; }
    public DateTime LastUpdate { get; set; }
    public bool ShouldUpdate
    {
        get
        {
            return ShouldUpdateExpression.Compile()(this);
        }
    }
    public static Expression<Func<Task, bool>> ShouldUpdateExpression
    {
        get
        {
            return t => t.LastUpdate < EntityFunctions.AddDays(DateTime.Now, 3);
        }
    }
}
在这种情况下,

Repository模式将提供更好的抽象。您可以按如下方式集中逻辑。在上下文中定义一个新属性TaskSource

public class MyDbContext : DbContext
{
    public DbSet<Task> Tasks { get; set; }
    public IQueryable<Task> TaskSource 
    { 
       get 
       { 
          return Tasks.Where(t => t.LastUpdate < EntityFunctions.AddDays(DateTime.Now, 3)); 
       }
    }
}

您需要将ShouldUpdate逻辑放入linq-to-enitites查询中。你可以使用EntityFunctions.AddDays来帮助你,就像一样

res = ctx.Tasks.Where(t => t.LastUpdate < EntityFunctions.AddDays(DateTime.Now, 3)).ToList();