Vous peut modifier l'accès à la propriété pour effectuer l'équivalent de 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);
}
note: Si la propriété est pas annulable (par exemple int?
ou double?
) une erreur se produit,
Modifier:
La version ci-dessus ce ne fonctionne que pour les propriétés nullables. Une autre version serait à l'ordre par une valeur par défaut pour les colonnes nullable et de faire la commande normale pour tous les autres alias: if (property is nullable) query.OrderBy(x => x.property == null ? default(basePropertyType) : x.property) else query.OrderBy(x => x.property)
La version pour cela ressemblerait à ceci:
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);
}
La valeur par défaut est personnalisable par tapez dans le DefaultTypeValues ou si aucune valeur n'est spécifiée, il sera par défaut au type nullable sous-jacent (ex pour int?
ce sera 0)
est-ce pas possible d'utiliser dans votre cas? 'OrderBy (x => x.property == null? 0: 1)' – Pac0