假设我在数据库中有一个名为“Stuff”的东西,其中包含一个名为“Id”的属性。从用户那里,我得到了一系列所选的范围对象(或者更确切地说,我从他们的输入中创建了这些对象),这些对象带有他们想要的Id。该结构的简化版本如下:
甚至更好的是,创建一个返回IQueryable的东西,这样我就可以这样做:
public struct Range<T> : IEquatable<Range<T>>, IEqualityComparer<Range<T>>
{
public T A;
public T B;
public Range(T a, T b)
{
A = a;
B = b;
}
...
}
因此,例如可以得到:
var selectedRange = new List<Range<int>>
{
new Range(1, 4),
new Range(7,11),
};
然后我想使用它创建一个谓词,仅选择那些值在这些之间的事物。例如,使用PredicateBuilder,我可以这样做:
var predicate = PredicateBuilder.False<Stuff>();
foreach (Range<int> r in selectedRange)
{
int a = r.A;
int b = r.B;
predicate = predicate.Or(ø => ø.Id >= a && ø.Id <= b);
}
然后:
var stuff = datacontext.Stuffs.Where(predicate).ToList();
这个可以工作!现在我想做的是创建一个通用的扩展方法来为我创建这些谓词。就像这样:
public static Expression<Func<T,bool>> ToPredicate<T>(this IEnumerable<Range<int>> range, Func<T, int> selector)
{
Expression<Func<T, bool>> p = PredicateBuilder.False<T>();
foreach (Range<int> r in range)
{
int a = r.A;
int b = r.B;
p = p.Or(ø => selector(ø) >= a && selector(ø) <= b);
}
return p;
}
这里的问题是由于选择器(ø)的调用而导致NotSupportedException崩溃:方法“System.Object DynamicInvoke(System.Object[])”没有支持SQL的翻译。
我想这是可以理解的。但是有没有什么办法可以解决这个问题?我想最终实现的目标是:
var stuff = datacontext.Stuffs.Where(selectedRange.ToPredicate<Stuff>(ø => ø.Id));
甚至更好的是,创建一个返回IQueryable的东西,这样我就可以这样做:
var stuff = datacontext.Stuffs.WhereWithin<Stuff>(selectedRange, ø => ø.Id); // Possibly without having to specify Stuff as type there...
那么,有什么想法吗?我真的很想让它工作,因为如果不这样做,我将得到大量的foreach代码块,创建谓词...
注意 1:当然,如果我能扩展到比 int 更多的东西,像 DateTime 等,那就太好了,但我不确定使用 >= 和 <= 运算符会怎样结束... CompareTo 在 Linq-to-Sql 中可行吗?如果不能,那么创建两个将没有问题。一个用于 int,另一个用于 DateTime,因为这主要是这些类型将被使用。
注意 2:它将用于报告,用户将能够根据不同的条件缩小输出范围。例如,我想要这份报告关于那些人和日期。