我正在使用我自己的IQueryable <>扩展方法来创建可链接查询,例如FindAll().FindInZip(12345).NameStartsWith("XYZ").OrderByHowIWantIt()等然后在延迟执行时创建基于我的单个查询扩展方法链.
但问题是,扩展链中的所有位置(FindXYZ,FindInZip等)将始终组合为AND,这意味着我无法做到这样的事情:
FindAll().FirstNameStartsWith("X").OrLastNameStartsWith("Z")因为我不知道如何在一个单独的Where方法中注入OR.
知道如何解决这个问题吗?
额外; 到目前为止,我理解如何将表达式链接为或者如果我将它们包装起来(例如CompileAsOr(FirstNameStartsWith("A").LastNameStartsWith("Z").OrderBy(..))
我想要做的虽然稍微复杂一点(并且PredicateBuilder在这里没有帮助......)因为我希望以后的IQueryable能够基本上访问先前建立的Where条件,而不必将它们包装起来以创建Or之间他们.
当每个扩展方法返回IQueryable <>时,我理解它应该知道某个地方的查询条件的当前状态,这使我相信应该有一些自动化的方法或在所有先前的Where条件中创建Or而不必包装你想要什么或者.
Mar*_*ell 11
我假设查询的不同部分仅在运行时已知,即您不能只||在where...中使用...
一个懒惰的选择是Concat- 但这往往导致差的TSQL等; 但是,我倾向于编写自定义Expressions.采用的方法取决于提供者是什么,因为LINQ-to-SQL支持EF的不同选项(例如) - 这在此具有真正的影响(因为你不能在EF中使用子表达式).你能告诉我们哪个?
这里有一些应该与LINQ-to-SQL一起使用的代码; 如果你构建一个.ToArray()表达式的数组(或列表,并调用),它应该工作正常; 示例是LINQ到对象,但应该仍然有效:
static void Main()
{
var data = (new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).AsQueryable();
var predicates = new List<Expression<Func<int, bool>>>();
predicates.Add(i => i % 3 == 0);
predicates.Add(i => i >= 8);
foreach (var item in data.WhereAny(predicates.ToArray()))
{
Console.WriteLine(item);
}
}
public static IQueryable<T> WhereAny<T>(
this IQueryable<T> source,
params Expression<Func<T,bool>>[] predicates)
{
if (source == null) throw new ArgumentNullException("source");
if (predicates == null) throw new ArgumentNullException("predicates");
if (predicates.Length == 0) return source.Where(x => false); // no matches!
if (predicates.Length == 1) return source.Where(predicates[0]); // simple
var param = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Invoke(predicates[0], param);
for (int i = 1; i < predicates.Length; i++)
{
body = Expression.OrElse(body, Expression.Invoke(predicates[i], param));
}
var lambda = Expression.Lambda<Func<T, bool>>(body, param);
return source.Where(lambda);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4962 次 |
| 最近记录: |