Динамическое упорядочение по строке - PullRequest
0 голосов
/ 09 июня 2019

Я создал расширение для IQueryable, так как я хотел бы сначала упорядочить по нулябельным датам, а затем упорядочить по самой дате, используя только строку свойства i.e "activeTo". Я создал код ниже:

public static IQueryable<T> Sort<T>(this IQueryable<T> source, string sortBy)
    {
        //create the expression tree that represents the generic parameter to the predicate
        var param = Expression.Parameter(typeof(T), "p");

        //create an expression tree that represents the expression p=>p.SortField.HasValue 
        var prop = Expression.Property(param, sortBy);

        var target = Expression.Constant(null, prop.Type);
        var bin = Expression.Equal(prop, Expression.Convert(target, prop.Type));

        var exp = Expression.Lambda(bin, param);

        string method = "OrderBy";
        Type[] types = new Type[] { source.ElementType, exp.Body.Type };
        var orderByCallExpression = Expression.Call(typeof(Queryable), method, types, source.Expression, exp);

        //now do the ThenBy bit,sending in the above expression to the Expression.Call
        exp = Expression.Lambda(prop, param);
        types = new Type[] { source.ElementType, exp.Body.Type };
        method = "ThenBy";
        var ThenByCallExpression = Expression.Call(typeof(Queryable), method, types, orderByCallExpression, exp);


        return source.Provider.CreateQuery<T>(ThenByCallExpression);
    }

Это расширение называется:

query.Sort("activeTo");

Что дает нижеследующий ответ:

 {
      "title": "test 5",
      "activeFrom": "2019-06-08T21:26:50.2833333",
      "activeTo": "2019-06-08T21:26:50.2833333",
 },
 {
      "title": "test 2",
      "activeFrom": "2019-06-08T21:28:45.65",
      "activeTo": null,
 }

Я ожидаю, что запись с activeTo равной нулю будет первой, однако это не так.

Кто-нибудь знает, что я делаю не так?

1 Ответ

1 голос
/ 09 июня 2019

Судя по комментариям, цель состоит в том, чтобы динамически сгенерировать выражение, которое сортирует значения null вперед.

Текущий код создает следующее выражение OrderBy(p => p.activeTo == null).ThenBy(p => p.activeTo == null).Это имеет два недостатка:

  • Сортирует null значения вперед, так как порядок сортировки bools равен false, true (поскольку их порядковые значения равны 0 и 1 соответственно).Поэтому при сравнении с null сначала собираются false дела, а затем true дела.
  • ThenBy повторяет OrderBy, но на самом деле предназначалось для излучения ThenBy(p => p.ActiveTo).

Первое можно решить, используя Expression.NotEqual вместо Expression.Equal для p => p != p.activeTo или OrderByDescending вместо OrderBy.В целом код должен быть:

public static IQueryable<T> Sort<T>(IQueryable<T> source, string sortBy)
{
    //create the expression tree that represents the generic parameter to the predicate
    var param = Expression.Parameter(typeof(T), "p");

    //create an expression tree that represents the expression p=>p.SortField.HasValue 
    var prop = Expression.Property(param, sortBy);

    var target = Expression.Constant(null, prop.Type);
    // NotEqual, to sort nulls before not-nulls
    var bin = Expression.NotEqual(prop, Expression.Convert(target, prop.Type));

    var exp = Expression.Lambda(bin, param);

    // OrderBy with the null comparison expression
    string method = nameof(Queryable.OrderBy);
    Type[] types = new Type[] { source.ElementType, exp.Body.Type };
    var orderByCallExpression = Expression.Call(typeof(Queryable), method, types, source.Expression, exp);

    // ThenBy with the property expression
    exp = Expression.Lambda(prop, param);
    types = new Type[] { source.ElementType, exp.Body.Type };
    method = nameof(Queryable.ThenBy);
    var ThenByCallExpression = Expression.Call(typeof(Queryable), method, types, orderByCallExpression, exp);

    return source.Provider.CreateQuery<T>(ThenByCallExpression);
}

Это дает следующее выражение: OrderBy(p => p.activeTo != null).ThenBy(p => p.activeTo).

Примечания : Следует отметить, что обычно OrderBy(p => p.activeTo) будетуже сортируют нулевые значения в начало, так как это порядок сортировки по умолчанию для строк, значений NULL и т. д.Однако это поведение может быть перезаписано в зависимости от конкретного типа и зависит от источника запроса.Поэтому я оставил его как OP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...