Хочу сделать пагинацию с фильтром (любое условие) и сортировкой по любому полю.
Допустим, в сервисе мы будем принимать 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();
Сборка персонального компьютера от Artline: умный выбор для современных пользователей