2017-08-28 55 views
1

我有一个自定义的IOrderedQueryable函数,如下所示。#使用表达式扩展的非空序列linq

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> srcQuery, 
string orderColumn, bool isAscending) 
{ 
    var type = typeof(T); 
    var property = type.GetProperty(orderColumn); 

    if (property == null) 
    throw new Exception("Column property \"" + orderColumn + "\" does not exist on the type \"" + typeof(T).FullName + "\""); 

    var parameter = Expression.Parameter(type, "p"); 
    var propertyAccess = Expression.MakeMemberAccess(parameter, property); 
    var orderByExp = Expression.Lambda(propertyAccess, parameter); 
    MethodCallExpression resultExp = 
    Expression.Call(typeof(Queryable),isAscending ? "OrderBy" : 
"OrderByDescending", new Type[] { type, property.PropertyType }, 
    srcQuery.Expression, Expression.Quote(orderByExp)); 

    return (IOrderedQueryable<T>)srcQuery.Provider.CreateQuery<T>(resultExp); 
} 

我想知道是否有无论如何,我可以通过与状态属性做一个订单!= null来显示不为空值,第一,然后在上面orderByExp表达

+0

这是不可能在你的情况下使用? 'OrderBy(x => x.property == null?0:1)' – Pac0

回答

2

你的空值可以修改属性访问以执行的query.OrderBy(x => x.property == null ? 0 : 1)

public static IOrderedQueryable<T> OrderByNull<T>(IQueryable<T> srcQuery, string orderColumn, bool isAscending) 
{ 
    var type = typeof(T); 
    var property = type.GetProperty(orderColumn); 

    if (property == null) 
     throw new Exception("Column property \"" + orderColumn + "\" does not exist on the type \"" + typeof(T).FullName + "\""); 

    var parameter = Expression.Parameter(type, "p"); 
    var propertyAccess = Expression.Condition(
     Expression.Equal(Expression.MakeMemberAccess(parameter, property), Expression.Constant(null, property.PropertyType)), 
     Expression.Constant(1), 
     Expression.Constant(0)); 

    var orderByExp = Expression.Lambda(propertyAccess, parameter); 
    MethodCallExpression resultExp =Expression.Call(typeof(Queryable), isAscending ? "OrderBy" : "OrderByDescending", new Type[] { type, typeof(int) }, 
    srcQuery.Expression, Expression.Quote(orderByExp)); 

    return (IOrderedQueryable<T>)srcQuery.Provider.CreateQuery<T>(resultExp); 
} 

注意等价的:如果该属性是不可为空(例如int?double?)将出现一个错误,

编辑

这仅适用于空的属性以上版本。另一个版本是由空列中的默认值订购并做正常的排序为人人,人又名:if (property is nullable) query.OrderBy(x => x.property == null ? default(basePropertyType) : x.property) else query.OrderBy(x => x.property)

的版本,将是这样的:

static Dictionary<Type, object> DefaultTypeValues = new Dictionary<Type, object> 
{ 
    { typeof(string), "" }, 
    // { typeof(DateTime?), new DateTime(1753,1,1) } // Min date for sql date 
     { typeof(DateTime?), new DateTime(9999,12,31} // Max date for sql date 
}; 

public static object GetDefaultValue(Type t) 
{ 
    object defaultValue; 
    if(!DefaultTypeValues.TryGetValue(t, out defaultValue)) 
    { 
     if(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) 
     { 
      defaultValue = Activator.CreateInstance(t.GetGenericArguments().Single()); 
     } 
     else 
     { 
      throw new NotSupportedException("Could not get default value for type " + t.FullName + " consider adding it in DefaultTypeValues"); 
     } 
    } 
    return defaultValue; 
} 
public static IOrderedQueryable<T> OrderBy<T>(IQueryable<T> srcQuery, string orderColumn, bool isAscending) 
{ 
    var type = typeof(T); 
    var property = type.GetProperty(orderColumn); 

    if (property == null) 
     throw new Exception("Column property \"" + orderColumn + "\" does not exist on the type \"" + typeof(T).FullName + "\""); 

    var parameter = Expression.Parameter(type, "p"); 
    // default sort is performed by o=> o.Prop 
    Expression propertyAccess = Expression.MakeMemberAccess(parameter, property); 
    var propType = property.PropertyType; 

    // If property is nullable we add teh null check 
    if (propType == typeof(string) || (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>))) 
    { 
     var defaultValue = GetDefaultValue(propType); 
     // If the property is nullable we sort by (o => o.Prop == null ? default(propType) : o.Prop) 
     propertyAccess = Expression.Condition(
      Expression.Equal(propertyAccess, Expression.Constant(null, propType)), 
      Expression.Constant(defaultValue, propType), 
      propertyAccess 
     ); 
    } 

    var orderByExp = Expression.Lambda(propertyAccess, parameter); 
    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), isAscending ? "OrderBy" : "OrderByDescending", new Type[] { type, propType }, 
    srcQuery.Expression, Expression.Quote(orderByExp)); 

    return (IOrderedQueryable<T>)srcQuery.Provider.CreateQuery<T>(resultExp); 
} 

默认值是通过定制键入DefaultTypeValues,或者如果没有指定值,它将默认为基础的可空类型(例如int?它将为0)

+0

嗨提香感谢您的回复。我目前的字段是可空的日期时间。上面的工作也是一样吗? – rockingmeister

+0

应该适用于任何'Nullable',我刚刚使用'DateTime?'进行了测试,并且查询生成了正确的结果 –

+0

对不起,我没有发布我的代码的最终版本。做一个小小的改变应该可行,但我现在无法测试,因为我在床上。如果它不起作用,请告诉我,明天我会找到解决方案。 –