Допустим, в моей базе данных есть нечто, называемое Stuff, со свойством Id. От пользователя я получаю последовательность выбранных объектов Range (или, скорее, я создаю их из их ввода) с идентификаторами, которые они хотят. Урезанная версия этой структуры выглядит следующим образом:
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 из-за вызова селектора (ø): Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to 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, так как это в основном типы, для которых будет использоваться. </p>
Примечание 2: Он будет использоваться для составления отчетов, когда пользователь сможет сузить то, что выходит, основываясь на разных вещах. Мол, я хочу этот отчет для тех людей и тех дат.