Как эффективно обрабатывать предложения Where и OrderBy - PullRequest
1 голос
/ 20 марта 2011

Мой бизнес-уровень передает всю необходимую информацию на уровень пользовательского интерфейса.Из того, что я прочитал, в общем, лучшая практика - отправлять извлеченные данные на уровень пользовательского интерфейса и избегать передачи запросов, таких как ObjectQuery.Моя проблема с этим подходом заключается в следующем:

Если я хочу создать гибкий бизнес-уровень, то я должен разрешить пользовательскому интерфейсу сортировать данные так, как это требуется.Извлечение отсортированных данных из базы данных и последующее использование их в пользовательском интерфейсе является для меня плохой практикой, поэтому единственный способ - как-то

Так какие у меня варианты?Есть ли способ сделать это так:

public void OrderByMethod(params ...) { .... }

, чтобы я мог назвать это так:

OrderByMethod(MyEntity.Property1, MyEntity.Property2 descending....);

Спасибо, Горан

Ответы [ 2 ]

1 голос
/ 20 марта 2011

Если вы не предоставляете IQueryable непосредственно для пользовательского интерфейса (вероятно, нет, потому что вы используете бизнес-уровень между пользовательским интерфейсом и уровнем доступа к данным), вы можете использовать пользовательский объект, передавая «список информации».Это может выглядеть следующим образом:

public class ListOptions<T>
{
    // Paging
    public int Page { get; set; }
    public int PageSize { get; set; }
    // Sorting
    public IList<SortOptions<T>> SortOptions { get; set; }
}

public class SortOptions<T>
{
    public Expression<Func<T, object>> SortProperty { get; set; }
    public bool IsDescending { get; set; }
}

Это будет использоваться в качестве параметра вашего бизнес-метода, возвращающего данные, а внутри бизнес-метода вы будете использовать пользовательские расширения для работы с IQueryable, предоставленными EF или репозиторием:

public static class QueryableExtensions
{
    public static IQueryable<T> ApplyListOptions<T>(this IQueryable<T> query, ListOptions<T> options)
    {
        if (options != null && options.SortOptions.Count > 0)
        {
            IOrderedQueryable<T> orderedQuery = query.ApplyOrderBy(options.SortOptions[0]);

            for (int i = 1; i < options.SortOptions.Count; i++)
            {
                orderedQuery = orderedQuery.ApplyThenBy(options.SortOptions[i]);
            }

            query = orderedQuery.ApplyPaging(options.Page, options.PageSize);
        }

        return query;
    }

    public static IOrderedQueryable<T> ApplyOrderBy<T>(this IQueryable<T> query, SortOptions<T> sortOption)
    {
        if (sortOption.IsDescending)
        {
            return query.OrderByDescending(sortOption.SortProperty);
        }

        return query.OrderBy(sortOption.SortProperty);
    }

    public static IOrderedQueryable<T> ApplyThenBy<T>(this IOrderedQueryable<T> query, SortOptions<T> sortOption)
    {
        if (sortOption.IsDescending)
        {
            return query.ThenByDescending(sortOption.SortProperty);
        }

        return query.ThenBy(sortOption.SortProperty);
    }

    public static IQueryable<T> ApplyPaging<T>(this IOrderedQueryable<T> query, int page, int pageSize)
    {
        if (pageSize > 0)
        {
            return query.Skip((page - 1)*pageSize).Take(pageSize);
        }

        return query;
    }
}

Таким образом, ваш метод обработки может выглядеть следующим образом:

public IEnumerable<User> GetUsers(ListOptions<User> listOptions)
{
    return _context.Users.ApplyListOptioins(listOptions).AsEnumerable();
}

И вы будете вызывать метод следующим образом:

var options = new ListOptions<User>
    {
        Page = 2,
        PageSize = 3,
        SortOptions = new List<SortOptions<User>>
            {
                new SortOptions<User> 
                    { 
                        IsDescending = false, 
                        SortProperty = u => u.LastName 
                    },
                new SortOptions<User> 
                    { 
                        IsDescending = true, 
                        SortProperty = u => u.FirstName 
                    }
            }
    };


var data = usersService.GetUsers(options);        
0 голосов
/ 20 марта 2011

Как данные передаются с одного слоя на другой? Это звучит так, будто вы используете простой шаблон хранилища, это правильно? Если да, то что обычно возвращают методы хранилища?

Часто рекомендуется, чтобы уровень данных и бизнес-уровень (при условии отсутствия жесткого разделения, например, уровня веб-службы) передавали данные в виде IEnumerable<T> или IQueryable<T>. Таким образом, когда данные попадают в пользовательский интерфейс, для кода пользовательского интерфейса очень легко продолжать манипулировать данными по мере необходимости (сортировка, разбиение по страницам и т. Д.).

На самом деле, если фактические данные не перечисляются до тех пор, пока они не попадут в пользовательский интерфейс, то он не должен даже делать запрос к базе данных до этого времени. Это допускает такие вещи, как логическая передача IEnumerable<T> всего результирующего набора в пользовательский интерфейс и последующее определение пользовательского интерфейса, что ему нужна только первая «страница» записей (путем вызова .Take() и получения только первых 10 например). Таким образом, вы можете использовать один очень простой метод репозитория во множестве разных мест по всему приложению, сокращая бизнес и логику отображения на уровне данных.

...