如何有效地处理Where和OrderBy子句

时间:2011-03-20 16:05:40

标签: c#-4.0 entity-framework-4 linq-to-entities

我的业务层将所有必需的信息传递给UI层。根据我的阅读,一般来说,最佳做法是将获取的数据发送到UI层,并避免传递像ObjectQuery这样的查询。我接下来会遇到这种方法的问题:

如果我要创建一个灵活的业务层,那么我应该允许UI根据需要对数据进行排序。从数据库中获取已排序的数据,然后在UI中使用它们对我来说是一种不好的做法,所以唯一的方法是以某种方式

那么我的选择是什么?有没有办法让它像这样:

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

所以我可以这样称呼它:

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

谢谢, 戈兰

2 个答案:

答案 0 :(得分:1)

如果您不直接将IQueryable公开给UI(您可能不会因为您在UI和数据访问层之间使用业务层),则可以使用自定义对象传递“列表信息”。它看起来像:

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; }
}

您将使用此作为业务方法的参数返回数据和内部业务方法,您将使用自定义扩展来处理EF或存储库提供的IQueryable

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);        

答案 1 :(得分:0)

如何将数据从一个层传递到另一个层?听起来好像你正在使用一个简单的存储库模式,这是正确的吗?如果是这样,存储库方法通常会返回什么?

数据层和业务层(假设没有硬分离,例如Web服务层)以IEnumerable<T>IQueryable<T>的形式传递数据通常是一种很好的做法。这样,当数据进入UI时,UI代码很容易根据需要继续操作数据(排序,分页等)。

实际上,如果实际数据不是枚举,直到它到达UI,那么在此之前它甚至不应该发出数据库请求。这允许将逻辑上的整个结果集的IEnumerable<T>传递给UI,然后让UI确定它只需要记录的第一个“页面”(通过调用.Take()并仅抓取前10个,例如)。这样,您可以在整个应用程序的许多不同位置使用单个非常简单的存储库方法,减少业务流程并将逻辑显示到数据层中。