Хочу сделать пагинацию с фильтром (любое условие) и сортировкой по любому полю.
Допустим, в сервисе мы будем принимать 4 параметра:
Task<List<UserResponse>> GetAllUsersAsync(int? skip = null,
int? take = null,
Expression<Func<User, bool>> wherePredicate = null,
SortOptions<User> sortOptions = null);
где UserResponse
- это DTO модель ответа, а SortOptions<T>
- это вспомогательный класс, который в свою очередь хранит предикат для метода OrderBy()
и тип сортировки:
public class SortOptions<T>
{
public Expression<Func<T, object>> Predicate { private set; get; }
public SortTypes SortType { private set; get; }
public SortOptions(Expression<Func<T, object>> predicate, SortTypes sortType)
{
Predicate = predicate;
SortType = sortType;
}
}
public enum SortTypes
{
ASC,
DESC
}
Сам вопрос заключается в том, как правильно всё это реализовать, без 8 if'ов.
То есть, если skip
параметр не указан, то LINQ запрос не изменится, так как от .Skip(skip.GetValueOrDefault())
ничего не скипнет и выберет данные с 0 позиции. Но вот .Take(null)
возьмёт ничего, вместо всего. Поэтому приходится .Take()
не использовать при null, например:
if (take == null)
{
_context.Users.OrderBy(x => x.FullNameNormalized)
.Skip(skip.GetValueOrDefault())
ToListAsync();
}
else
{
_context.Users.OrderBy(x => x.FullNameNormalized)
.Skip(skip.GetValueOrDefault())
.Take(take.Value)
.ToListAsync();
}
Так же есть .OrderBy()
и .OrderByDescending()
для ASC и DESC сортировки соответственно. .Where()
тоже не укажешь с null. Вспоминая комбинаторику, имея 3 опциональных параметров с двумя состояниями, получаем 8 вариантов. В итоге получается подобная структура:
if (sortOptions.SortType == SortTypes.ASC)
{
if (take == null)
{
if (wherePredicate == null)
{
...
}
else
{
...
}
}
else
{
if (wherePredicate == null)
{
...
}
else
{
...
}
}
}
else
{
if (take == null)
{
if (wherePredicate == null)
{
...
}
else
{
...
}
}
else
{
if (wherePredicate == null)
{
...
}
else
{
...
}
}
}
Ваш код можно существенно упростить следующим образом:
IQueryable<User> query = _context.Users;
if (skip != null)
query = query.Skip(skip.Value);
if (take != null)
query = query.Take(take.Value);
if (wherePredicate != null)
query = query ...
// другие условия ...
return query.ToListAsync();
Мой вариант с использованием ?:
IQueryable<User> query = _context.Users;
query = wherePredicate != null ? query.Where(wherePredicate) : query;
query = sortOptions.Predicate == null ? query :
sortOptions.SortType == SortTypes.ASC ? query.OrderBy(sortOptions.Predicate) : query.OrderByDescending(sortOptions.Predicate);
query = query.Skip(skip.GetValueOrDefault());
query = take != null ? query.Take(take.Value) : query;
List<User> users = await query.ToListAsync();
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Подскажите, каким пространством при работе с изображениями лучше пользоваться в новых проектах?
Хотел начать работать с PhantomJS, установил через nuget сам Selenium, SeleniumPhantomJS
Возникла проблема при создании сервиса(systemd) в Linux для автоматического запуска Web App: нет никаких признаков соединения с Oracle БД
Есть скрипт, который обновляет таблицу с ордерами на сайте каждые 3 секунды, но когда в таблице остается один ордер и его скупают, то таблица...