Include derived property into a linq to entity query

拜拜、爱过 提交于 2020-01-02 05:56:19

问题


Here is a simple project based on a Poco class named Task:

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);
        }
    }
}

What I want to do is to query the context dbset including in the where clause the ShouldUpdate derived property.

The "first query works fine" (I can't write it in a single line but it doesn't matter).

As you know, we get a NotSupportedException on the "second query", with the following message: The specified type member 'ShouldUpdate' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

That's right and I can understand why it happen, but I need to encapsulate the derived information inside the Task object so I can display the property in a grid or use it in every other place, without duplicating the logic behind it.

Is there a smart technique to do this?

NB: What is the technical name of the ShouldUplate property? derived? calculated? computed?


回答1:


Finally i found THE solution.. You can store the partial queries (Expressions) in static fileds and use them like this:

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);
        }
    }
}



回答2:


Repository pattern would provide a better abstraction in this case. You can centralize the logic as follows. Define a new property TaskSource in your context.

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)); 
       }
    }
}



回答3:


You need to put the ShouldUpdate logic inside the linq-to-enitites query. You can use EntityFunctions.AddDays to help you out like so

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


来源:https://stackoverflow.com/questions/9327438/include-derived-property-into-a-linq-to-entity-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!