【问题标题】:#Order by Not Null using expression Extension linq#Order by Not Null 使用表达式 Extension linq
【发布时间】:2017-08-28 16:39:09
【问题描述】:

我有一个自定义的 IOrderedQueryable 函数,如下所示。

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 表达式中的空值

【问题讨论】:

  • 这不可能在您的情况下使用吗? OrderBy(x =&gt; x.property == null ? 0 : 1)

标签: c# linq lambda iqueryable


【解决方案1】:

您可以修改属性访问以执行query.OrderBy(x =&gt; 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 =&gt; x.property == null ? default(basePropertyType) : x.property) else query.OrderBy(x =&gt; 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)

【讨论】:

  • 嗨 Titian 感谢您的回复。我目前拥有的字段是 Nullable 日期时间。上述方法也适用吗?
  • 应该适用于任何Nullable,我刚刚用DateTime? 进行了测试,并且查询是正确生成的
  • 抱歉,我没有发布我的代码的最终版本。做一个小的改变应该可以工作,但我现在不能测试,因为我在床上。如果它不起作用,请告诉我,我明天会找到解决方案。
  • 嗨 Titian 非常感谢您的回复。我只是尝试调试代码,我之前提到的错误工作正常。但是现在我收到另一个错误,指出{“参数类型不匹配”}。当我有一个不可为空的属性时会发生这种情况-> {System.DateTime CreateDate}
  • @rockingmeister 好的,但问题变成了在这种情况下您希望它做什么......由于最初的请求是按天气排序,因此它是否为空。如果该列是 DateTime 它不能为空.. 那么它应该做什么排序呢?
猜你喜欢
  • 1970-01-01
  • 2019-01-03
  • 2013-07-07
  • 2016-05-26
  • 2012-02-05
  • 1970-01-01
  • 2011-06-28
  • 2016-04-12
  • 2017-10-06
相关资源
最近更新 更多