问题
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