2011-05-30 104 views
2

我有这个项目与EF4设置,我使用LINQ to Entities来形成查询。LINQ to Entities - 左外连接与条件where子句

我在查询中遇到了一些麻烦,涉及大量的条件where子句和几个左外连接。

我用下面的扩展方法(我发现here)部分解决了条件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. 

所以,我想知道如果有人知道我该如何解决这个问题?

回答

4

问题是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(), 
    (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

这工作。诀窍确实是将WhereIf移出SelectMany。我试着运行生成的SQL来确认,并产生了期望的结果。非常感谢! – Eirik 2011-05-30 08:42:12

0

为什么不能做Where(timestamp == null || c.Timestamp > timestamp)