Включить производное свойство в запрос linq to entity - PullRequest
4 голосов
/ 17 февраля 2012

Вот простой проект, основанный на классе Poco с именем 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);
        }
    }
}

Что я хочу сделать, это запросить контекст dbset, включая в предложении where производное свойство ShouldUpdate.

«Первый запрос работает нормально» (я не могу написать его в одной строке, но это не имеет значения).

Как вы знаете, мы получаем NotSupportedException для "второго запроса" со следующим сообщением: Указанный член типа 'ShouldUpdate' не поддерживается в LINQ to Entities. Поддерживаются только инициализаторы, элементы сущностей и свойства навигации сущностей.

Это верно, и я могу понять, почему это происходит, но мне нужно инкапсулировать производную информацию в объекте Task, чтобы я мог отобразить свойство в сетке или использовать его в любом другом месте, не дублируя логику, стоящую за ним. .

Есть ли умная техника для этого?

NB. Какое техническое имя свойства ShouldUplate? получен? рассчитывается? вычислен

Ответы [ 3 ]

3 голосов
/ 01 июня 2012

Наконец я нашел решение .. Вы можете хранить частичные запросы (выражения) в статических полях и использовать их следующим образом:

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);
        }
    }
}
1 голос
/ 17 февраля 2012

Шаблон репозитория обеспечит лучшую абстракцию в этом случае. Вы можете централизовать логику следующим образом. Определите новое свойство 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)); 
       }
    }
}
0 голосов
/ 17 февраля 2012

Вам необходимо поместить логику ShouldUpdate в запрос linq-to-enitites.Вы можете использовать EntityFunctions.AddDays , чтобы помочь вам вот так

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