Я использую этот фрагмент ниже для упорядочивания моих запросов Linq динамически и отлично работает. Я не очень разбираюсь в сложных или сложных запросах linq, но мне нужно, чтобы при использовании возрастающего значения эти значения NULL были последними и наоборот.
Итак, если мое имя свойства было целым числом, а значения столбца были 1, 3, 5, все NULL-строки были бы в конце, а не в начале по умолчанию. Что я могу добавить к этому выражению, чтобы это произошло?
Этот код работает с инфраструктурой сущностей и все еще нуждается в сравнении NULL.
Пример
list.OrderBy("NAME DESC").ToList()
Класс
public static class OrderByHelper
{
public static IOrderedQueryable<T> ThenBy<T>(this IEnumerable<T> enumerable, string orderBy)
{
return enumerable.AsQueryable().ThenBy(orderBy);
}
public static IOrderedQueryable<T> ThenBy<T>(this IQueryable<T> collection, string orderBy)
{
if (string.IsNullOrWhiteSpace(orderBy))
orderBy = "ID DESC";
IOrderedQueryable<T> orderedQueryable = null;
foreach (OrderByInfo orderByInfo in ParseOrderBy(orderBy, false))
orderedQueryable = ApplyOrderBy<T>(collection, orderByInfo);
return orderedQueryable;
}
public static IOrderedQueryable<T> OrderBy<T>(this IEnumerable<T> enumerable, string orderBy)
{
return enumerable.AsQueryable().OrderBy(orderBy);
}
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> collection, string orderBy)
{
if (string.IsNullOrWhiteSpace(orderBy))
orderBy = "ID DESC";
IOrderedQueryable<T> orderedQueryable = null;
foreach (OrderByInfo orderByInfo in ParseOrderBy(orderBy, true))
orderedQueryable = ApplyOrderBy<T>(collection, orderByInfo);
return orderedQueryable;
}
private static IOrderedQueryable<T> ApplyOrderBy<T>(IQueryable<T> collection, OrderByInfo orderByInfo)
{
string[] props = orderByInfo.PropertyName.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
string methodName = String.Empty;
if (!orderByInfo.Initial && collection is IOrderedQueryable<T>)
{
if (orderByInfo.Direction == SortDirection.Ascending)
methodName = "ThenBy";
else
methodName = "ThenByDescending";
}
else
{
if (orderByInfo.Direction == SortDirection.Ascending)
methodName = "OrderBy";
else
methodName = "OrderByDescending";
}
return (IOrderedQueryable<T>)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 });
}
private static IEnumerable<OrderByInfo> ParseOrderBy(string orderBy, bool initial)
{
if (String.IsNullOrEmpty(orderBy))
yield break;
string[] items = orderBy.Split(',');
foreach (string item in items)
{
string[] pair = item.Trim().Split(' ');
if (pair.Length > 2)
throw new ArgumentException(String.Format("Invalid OrderBy string '{0}'. Order By Format: Property, Property2 ASC, Property2 DESC", item));
string prop = pair[0].Trim();
if (String.IsNullOrEmpty(prop))
throw new ArgumentException("Invalid Property. Order By Format: Property, Property2 ASC, Property2 DESC");
SortDirection dir = SortDirection.Ascending;
if (pair.Length == 2)
dir = ("desc".Equals(pair[1].Trim(), StringComparison.OrdinalIgnoreCase) ? SortDirection.Descending : SortDirection.Ascending);
yield return new OrderByInfo() { PropertyName = prop, Direction = dir, Initial = initial };
initial = false;
}
}
private class OrderByInfo
{
public string PropertyName { get; set; }
public SortDirection Direction { get; set; }
public bool Initial { get; set; }
}
private enum SortDirection
{
Ascending = 0,
Descending = 1
}