LINQ to Entities-带条件where子句的左外部联接

问题描述

|| 我已经使用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 to Entities时,无法识别扩展方法。 这是查询的一部分:
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.
因此,我想知道是否有人知道如何解决此问题?     

解决方法

        问题在于EF无法识别
SelectMany
中的
WhereIf
。将查询重写为方法语法会产生类似以下内容(查询不完整):
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(),c }
  )
  .WhereIf(timestamp != null,x => x.c.Timestamp > timestamp)
您可以通过将查询转换为
ObjectQuery
并调用方法
ToTraceString
来检查生成的SQL,以查看是否真正获得了所需的内容:
var query = context.Entities.OfType<Patient>() ...
Console.WriteLine(((ObjectQuery) query).ToTraceString());
    ,        为什么不
Where(timestamp == null || c.Timestamp > timestamp)
?