LINQ to Entities - левое внешнее объединение с условным предложением where - PullRequest
2 голосов
/ 30 мая 2011

У меня есть этот проект, настроенный с EF4, и я использую LINQ to Entities для формирования запросов.

У меня возникли проблемы с запросом, который включает в себя множество условных выражений where и несколько левых внешних объединений.

Я частично решил условные условия where с помощью следующего метода расширения (который я нашел здесь ).

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, bool>> predicate)
    {
        if (condition)
            return source.Where(predicate);
        else
            return source;
    }

У меня сейчас проблема в том, что LINQк сущностям не распознает метод расширения, когда я использую его в соединенных таблицах.

Вот часть запроса:

from p in context.Entities.OfType<Patient>()
    .WhereIf(!string.IsNullOrEmpty(name), p => p.Name.Contains(name))
from c in context.Contacts
    .Where(cp => cp.EntityID == p.EntityId).DefaultIfEmpty()
    .WhereIf(timestamp != null, c => c.Timestamp > timestamp)

Я говорю, что частично решен, потому что он прекрасно работаетв первый раз (имя пациента) в этом запросе, но во второй раз (отметка времени) он выдает мне эту ошибку:

LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[x.Contact] WhereIf[Contact](System.Linq.IQueryable`1[x.Contact], Boolean, System.Linq.Expressions.Expression`1[System.Func`2[x.Contact,System.Boolean]])' method, and this method cannot be translated into a store expression.

Итак, мне интересно, если кто-нибудь знает, как я могу это исправить?

Ответы [ 2 ]

4 голосов
/ 30 мая 2011

Проблема в том, что EF не может распознать WhereIf внутри SelectMany. Переписав ваш запрос в синтаксис метода, вы получите что-то вроде этого (запрос не завершен):

context.Entities.OfType<Patient>()
  .WhereIf(!string.IsNullOrEmpty(name), p => p.Name.Contains(name))
  .SelectMany(
    p => context.Contacts
      .Where(cp => cp.EntityID == p.EntityId).DefaultIfEmpty()
      .WhereIf(timestamp != null, c => c.Timestamp > timestamp),
    (p, c) => new { p, c }
  )

Проблема последняя WhereIf. Вы должны быть в состоянии переместить его за пределы SelectMany:

context.Entities.OfType<Patient>()
  .WhereIf(!string.IsNullOrEmpty(name), p => p.Name.Contains(name))
  .SelectMany(
    p => context.Contacts
      .Where(cp => cp.EntityID == p.EntityId).DefaultIfEmpty(),
    (p, c) => new { p, c }
  )
  .WhereIf(timestamp != null, x => x.c.Timestamp > timestamp)

Вы можете проверить полученный SQL-запрос, чтобы узнать, действительно ли вы получите то, что вам действительно нужно, приведя запрос к ObjectQuery и вызвав метод ToTraceString:

var query = context.Entities.OfType<Patient>() ...
Console.WriteLine(((ObjectQuery) query).ToTraceString());
0 голосов
/ 30 мая 2011

Почему бы не сделать Where(timestamp == null || c.Timestamp > timestamp)?

...