2017-08-28 56 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

對不起,我沒有發佈我的代碼的最終版本。做一個小小的改變應該可行,但我現在無法測試,因爲我在牀上。如果它不起作用,請告訴我,明天我會找到解決方案。 –