Keep NULL rows last on Dynamic Linq Order By

后端 未结 4 1475
一向
一向 2021-02-14 00:28

I am using this snippet below for Ordering my Linq queries dynamically and works great. I am not great at reflection or complex linq queries but I need a way that when ascendin

4条回答
  •  北海茫月
    2021-02-14 00:38

    One approach is to pass an additional expression for testing for null into the method, and use it in an additional OrderBy/ThenBy clause.

    Two OrderBy clauses would be produced - the first one will be on nullOrder, while the second one will be on the actual property.

    private static IOrderedQueryable ApplyOrderBy(IQueryable collection, OrderByInfo orderByInfo, Expression> nullOrder) {
        ...
        if (!orderByInfo.Initial && collection is IOrderedQueryable) {
            if (orderByInfo.Direction == SortDirection.Ascending)
                methodName = "ThenBy";
            else
                methodName = "ThenByDescending";
        } else {
            if (orderByInfo.Direction == SortDirection.Ascending)
                methodName = "OrderBy";
            else
                methodName = "OrderByDescending";
        }
        if (nullOrder != null) {
            collection = (IQueryable)typeof(Queryable).GetMethods().Single(
                    method => method.Name == methodName
                            && method.IsGenericMethodDefinition
                            && method.GetGenericArguments().Length == 2
                            && method.GetParameters().Length == 2)
                    .MakeGenericMethod(typeof(T), type)
                    .Invoke(null, new object[] { collection, nullOrder });
            // We've inserted the initial order by on nullOrder,
            // so OrderBy on the property becomes a "ThenBy"
            if (orderByInfo.Direction == SortDirection.Ascending)
                methodName = "ThenBy";
            else
                methodName = "ThenByDescending";
        }
        // The rest of the method remains the same
        return (IOrderedQueryable)typeof(Queryable).GetMethods().Single(
                    method => method.Name == methodName
                            && method.IsGenericMethodDefinition
                            && method.GetGenericArguments().Length == 2
                            && method.GetParameters().Length == 2)
                    .MakeGenericMethod(typeof(T), type)
                    .Invoke(null, new object[] { collection, lambda });
    }
    

    The caller would need to pass a null checker explicitly. Passing null for non-nullable fields should work. You can construct them once, and pass as needed:

    static readonly Expression> NullStringOrder = s => s == null ? 1 : 0;
    static readonly Expression> NullIntOrder = i => !i.HasValue ? 1 : 0;
    static readonly Expression> NullLongOrder = i => !i.HasValue ? 1 : 0;
    

提交回复
热议问题