【发布时间】:2016-06-29 17:25:27
【问题描述】:
我正在构建一种方法,该方法采用一个或多个条件来使用 LINQ 查询数据库。我做了这个:
public ICollection<MyClass> FindAllBy(params Expression<Func<MyClass, bool>>[] criteria)
{
using (var ctx = new MyContext())
{
IQueryable<MyClass> result = ctx.MyClasses.AsNoTracking();
if (criteria != null && criteria.Length > 0)
{
foreach (var item in criteria)
{
result = result.Where(item);
}
}
return result.ToList();
}
}
这样的效果是,如果我查找一个 ID 为 1 的对象和一个 ID 为 2 的对象,我什么也得不到,因为没有一行 ID 为 1 和 2。所以我需要一个 OR 子句。我找到了这个页面:
http://www.albahari.com/nutshell/predicatebuilder.aspx
其中有一个 PredicateBuilder 类,我曾经这样做过:
public ICollection<PhotoFile> FindAllBy(params Expression<Func<PhotoFile, bool>>[] criteria)
{
using (var ctx = new CotanContext())
{
var predicate = PredicateBuilder.False<PhotoFile>();
if (criteria != null && criteria.Length > 0)
{
foreach (var item in criteria)
{
predicate = predicate.Or(item);
}
}
return ctx.PhotoFiles.Where(predicate).ToList();
}
}
我的代码与页面略有不同,因为我将表达式传递给方法,然后将其传递给 Predicate.Or 方法。
上述方法给出The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. 错误。这是有道理的,因为实体框架不知道如何将此代码转换为有效的查询。
链接站点上的解决方案是下载他们的 Nuget 包或源代码,这使得该代码可以工作。但是,我真的不喜欢为单个函数添加数百行未知且看似未经测试的代码,在我看来,微软应该在很久以前就将其内置到 LINQ 中。我项目的首席开发人员过去也曾强烈建议不要使用并非直接来自 Microsoft 的未知软件包。我正在处理敏感信息,所以我宁愿安全也不要后悔。
那么,我的问题是:有什么方法可以在 LINQ 中获取 OR 函数而无需使用外部 Nuget 包?
【问题讨论】:
-
您真的需要将子句传递到您的函数中吗?为什么不返回一个 IQueryable 并让调用者弄清楚该怎么做?
-
至少在第一种方法中,这就是我正在做的。我只在调用 ToList() 时将 IQueryable 转换为 IEnumerable。我使用接受表达式并返回另一个 IQueryable 的 Where() 重载。而第二个示例中的 Or 方法只返回另一个 Expression,因此也没有数据库调用。
-
感谢 Ivan,这很简单,我可以为它编写自己的测试。它也足够短,其他人也可以查看。
-
@ohyeah 不,我的意思是,从您的存储库返回 IQueryable 并允许服务应用自己的过滤器。您在这里所做的基本上是阻止 fluent API 发挥作用。