问题描述
||
我已经使用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)
?