Запрос с опциональными OrderBy, Where и Take

188
19 ноября 2018, 03:10

Хочу сделать пагинацию с фильтром (любое условие) и сортировкой по любому полю.

Допустим, в сервисе мы будем принимать 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
        {
            ...
        }
    }
} 
Answer 1

Ваш код можно существенно упростить следующим образом:

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();
Answer 2

Мой вариант с использованием ?:

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();
READ ALSO
Работа с изображением через System.Windows.Media VS System.Drawing

Работа с изображением через System.Windows.Media VS System.Drawing

Подскажите, каким пространством при работе с изображениями лучше пользоваться в новых проектах?

197
В списке using отсутствует OpenQA.Selenium.PhantomJS

В списке using отсутствует OpenQA.Selenium.PhantomJS

Хотел начать работать с PhantomJS, установил через nuget сам Selenium, SeleniumPhantomJS

183
При создании сервиса на Linux нет соединения с БД Oracle

При создании сервиса на Linux нет соединения с БД Oracle

Возникла проблема при создании сервиса(systemd) в Linux для автоматического запуска Web App: нет никаких признаков соединения с Oracle БД

203
Не обновляется таблица

Не обновляется таблица

Есть скрипт, который обновляет таблицу с ордерами на сайте каждые 3 секунды, но когда в таблице остается один ордер и его скупают, то таблица...

192