在EF查询中指定动态“OrderBy”/“OrderByDescening”的最佳方法

时间:2016-05-11 16:27:21

标签: c# .net entity-framework

我有一个包含许多不同排序顺序的枚举:

public enum LogSortOrder
{
    DateTimeAsc = 1,

    DateTimeDesc = 2,

    LevelAsc = 3,

    LevelDesc = 4,

    MessageAsc = 5,

    MessageDesc = 6
}

我不想在switch语句中构建我的查询,而是想知道是否有更高效或更优雅的方法来实现这一点,所以我不需要将我的查询分开并且有一个丑陋的开关块,如下所示:

var query = context.Set<Log>().AsQueryable();

            switch ( sortOrder )
            {
                case LogSortOrder.LevelAsc:
                    query = query.OrderBy( l => l.Level );
                    break;

                case LogSortOrder.LevelDesc:
                    query = query.OrderByDescending( l => l.Level );
                    break;

                case LogSortOrder.MessageAsc:
                    query = query.OrderBy( l => l.Message );
                    break;

                case LogSortOrder.MessageDesc:
                    query = query.OrderByDescending( l => l.Message );
                    break;

                case LogSortOrder.DateTimeAsc:
                    query = query.OrderBy( l => l.Date );
                    break;

                default:
                    query = query.OrderByDescending( l => l.Date );
                    break;
            }

            return await query
                .Skip( offset )
                .Take( limit )
                .ToListAsync();

3 个答案:

答案 0 :(得分:1)

好吧,您可以使用System.Linq.Expressions构建它。我不会称之为更高效或更优雅。可能更灵活(允许轻松添加新的enum成员),但同时更容易出错。

var query = context.Set<Log>().AsQueryable();

var sortInfo = sortOrder.ToString();
bool descending = sortInfo.EndsWith("Desc");
var propertyName = sortInfo.Substring(0, sortInfo.Length - (descending ? "Desc" : "Asc").Length);
var parameter = Expression.Parameter(typeof(Log), "log");
var selector = Expression.Lambda(Expression.PropertyOrField(parameter, propertyName), parameter);
query = query.Provider.CreateQuery<Log>(Expression.Call(
    typeof(Queryable), 
    "OrderBy" + (descending ? "Descending" : null), 
    new [] { parameter.Type, selector.Body.Type},
    query.Expression, Expression.Quote(selector)));

// ...

答案 1 :(得分:1)

我认为最简单,最直接的方法是保持逻辑,但将其包装在扩展方法中,以便在使用它时看起来更好。这也更容易维护。

public static class SortHelper
{
    public static IOrderedQueryable<Log> SortFromCommand(this IQueryable<Log> entities, LogSortOrder sortOrder)
    {
        IOrderedQueryable<Log> ordered;

        switch (sortOrder)
        {
            case LogSortOrder.LevelAsc:
                ordered = entities.OrderBy(l => l.Level);
                break;

            case LogSortOrder.LevelDesc:
                ordered = entities.OrderByDescending( l => l.Level );
                break;

            case LogSortOrder.MessageAsc:
                ordered = entities.OrderBy( l => l.Message );
                break;

            case LogSortOrder.MessageDesc:
                ordered = entities.OrderByDescending( l => l.Message );
                break;

            case LogSortOrder.DateTimeAsc:
                ordered = entities.OrderBy( l => l.Date );
                break;

            default:
                ordered = entities.OrderByDescending( l => l.Date );
                break;
        }

        return ordered;
    }
}

用法:

var sortCommand = LogSortOrder.LevelAsc;
var results = context.Set<Log>().AsQueryable()
                                .SortFromCommand(sortCommand)
                                .Skip(10)
                                .ToList();

答案 2 :(得分:0)

您可以使用可以将字符串转换为linq表达式的库,如下所示: https://www.nuget.org/packages/System.Linq.Dynamic.Library/

此时您可以(例如)将您的枚举值更改为字符串(即MessageAsc = "Message"query = query.OrderBy(sortOrder);

然后你的switch语句将缩减为:

PieChart