Контекст — этот вопрос: Сортировка по DayOfWeek, неделя начинается с понедельника
Хочется отрефакторить код сортировки и вместо непонятной лямбды
s => ((int)s.DayOfWeek + 6) % 7
написать что-то вроде
s => GetDayNumberInWeek(s.DayOfWeek, weekStartsWith: DayOfWeek.Monday)
Выясняется, что деревья выражений не поддерживают именованные параметры, т.е. придется писать менее понятно:
s => GetDayNumberInWeek(s.DayOfWeek, DayOfWeek.Monday)
Пусть так, но как это сделать? Если написать
static int GetDayNumberInWeek(DayOfWeek dayOfWeek, DayOfWeek weekStartsWith)
{
int daysInWeek = 7;
return ((int)dayOfWeek + daysInWeek - (int)weekStartsWith) % daysInWeek;
}
То сортировка, понятно, начнет выполняться на клиентской стороне, а этого не хочется.
Если я возвращаю из метода любой Expression, то EF ругается на отсутствие реализации IComparable
Есть ли вообще решение у такой задачи?
Ответ
Вам нужно генерировать всю лямбду целиком, а не только правую часть.
На более простом примере, чтобы не шумело создание Body:
Пусть у вас есть:
context.Schedules
.OrderBy(s => s.DayOfWeek)
.ToList();
И вы хотите строить key selector для динамически:
Выносим селектор целиком:
context.Schedules
.OrderBy(BuildKeySelector())
.ToList();
private static Expression
И разворачиваем сгенерированный код:
context.Schedules
.OrderBy(BuildDayOfWeekSelector())
.ToList();
private static Expression
// правая часть, тут должно быть более сложное дерево
var body = Expression.MakeMemberAccess(
parameter,
typeof(Schedule).GetProperty("DayOfWeek"));
var lambda = Expression.Lambda
return lambda;
}
Если надо отвязать BuildDayOfWeekSelector от Schedule - просто сделайте его Generic (но придется указывать тип при вызове).
private static Expression
var body = Expression.MakeMemberAccess( // правая часть
parameter,
typeof(T).GetProperty("DayOfWeek"));
var lambda = Expression.Lambda
return lambda;
}
Остаток динамики - параметр weekStartsWith - спускайте параметром в BuildKeySelector и используйте при построении body как Expression.Constant(weekStartsWith);
Точное дерево, которое надо строить руками, можно легко подсмотреть - сделать extract local для сгенерированной компилятором лямбды, и развернуть ее в отладчике.
Комментариев нет:
Отправить комментарий