我使用EF4设置了这个项目,我正在使用LINQ to Entities来形成查询。
我遇到了一些涉及大量条件where子句和多个左外连接的查询的问题。
我已经部分解决了带有以下扩展方法的条件where子句(我发现here)。
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.
所以,我想知道是否有人知道如何解决这个问题?
答案 0 :(得分:4)
问题是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());
答案 1 :(得分:0)
为什么不Where(timestamp == null || c.Timestamp > timestamp)
?