实体框架的导航属性在为空之后为空

问题描述:

我使用以下代码通过表达式转换顺序,因此也可以排序可以为空的列。实体框架的导航属性在为空之后为空

protected virtual Expression<Func<T, object>> GetSorting(string ordering) 
{ 
     Expression<Func<T, object>> expression = default(Expression<Func<T, object>>); 
     IEnumerable<Order> sortObjects = string.IsNullOrEmpty(ordering) ? null : JsonConvert.DeserializeObject<IEnumerable<Order>>(ordering); 
     if (sortObjects != null) 
     { 
      foreach (Order sortObject in sortObjects) 
      { 
       Expression<Func<T, object>> currentExpression = this.GetExpression(sortObject.Property); 
       expression = this.CombineExpressions(expression, currentExpression); 
      } 
     } 

     return expression; 
} 

private Expression<Func<T, object>> GetExpression(string propertyName) 
{ 
     Type type = typeof(T); 
     ParameterExpression parameter = Expression.Parameter(type, "x"); 
     MemberExpression propertyReference = Expression.Property(parameter, propertyName); 
     Expression conversion = Expression.Convert(propertyReference, typeof(object)); 
     Expression<Func<T, object>> currentExpression = Expression.Lambda<Func<T, object>>(conversion, new[] { parameter }); 
     return currentExpression; 

} 

private Expression<Func<T, object>> CombineExpressions(Expression<Func<T, object>> expression, Expression<Func<T, object>> currentExpression) 
{ 
     if (expression == default(Expression<Func<T, object>>)) 
     { 
      expression = currentExpression; 
     } 
     else 
     { 
      // Combine the two expressions' body together 
      BinaryExpression body = Expression.AndAlso(expression.Body, currentExpression.Body); 
      ParameterExpression[] parameters = new ParameterExpression[1] { Expression.Parameter(typeof(T), expression.Parameters.First().Name) }; 

      // Convert the BinaryExpression to the requested type 
      Expression<Func<T, object>> lambda = Expression.Lambda<Func<T, object>>(body, parameters); 

      expression = lambda; 
     } 

     return expression; 
} 

该代码完全适用于所有非导航性能,但它好像在导航性能不再查询。我用一个选择表达式来加载导航属性,就像这样:

protected override Expression<Func<Resource, ResourceViewModel>> Selector 
{ 
     get 
     { 
      return (x) => new ResourceViewModel() 
      { 
       ResourceId = x.ResourceId, 
       DisplayName = x.DisplayName,     
       ResourceType = x.ResourceType != null ? x.ResourceType.Name : string.Empty, 
      } 
     } 
} 

如果我没有什么顺序由导航属性加载。但只要有任何要订购的东西,导航属性就为空。如果我跳过三元操作并直接进入ResourceType.Name属性,我会得到一个异常,告诉我lambda_method抛出了NullReference异常。

我知道订购导航属性不起作用,但这不是问题。按“常规”属性排序会导致问题。

对这个有什么想法?

+1

让从这里开始。按表达式排序不能像谓词那样组合,但需要与'OrderBy/ThenBy'链接。这意味着你需要一种不同的方法 - 'IQueryable '扩展方法而不是表达式返回方法。当按表达式应用顺序时,不需要将它们转换为“object”类型。 –

+0

我同意你的第一个陈述,但你的第二种方法似乎并不正确。您需要为排序定义一个TKey类型。因为我的场景必须能够接受任何类型,所以我只使用了对象。但是这两个陈述都不适合我的问题。我已经为这个问题创建了一个解决方法,但我仍然好奇这是否可能。 – hbulens

+0

问题在于'Expression >'是不一样的(不能转换成)'Expression >'。另外,当你使用像这样的表达式时,得到的表达式体不是成员访问,而是可以从上面得到的,但是转换。为什么你认为'OrderBy/ThenBy'声明了第二个泛型参数,如果它很容易忽略它。 –

原来这个问题并不像我想的那么复杂。问题是我创建了错误的表达式树。您可以嵌套表达式,以便您可以导航到属性的属性。

下面的解决方案应该解释(这不是我实际上是如何解决这个问题,但它应该清楚):

private Expression<Func<T, object>> GetExpression(string parentClass, string propertyName) 
{ 
    Type type = typeof(T); 
    ParameterExpression parameter = Expression.Parameter(type, "x"); 

    // Get parent class expression 
    // Will result in (x) => x.MyNavigationPropertyWhichIsAClass 
    MemberExpression propertyReference1 = Expression.Property(parameter, parentclass); 

    // Navigate to the property of the navigation property class 
    // Will result in (x) => x.MyNavigationPropertyWhichIsAClass.MyPropertyIWantToSort 
    MemberExpression propertyReference2 = Expression.Property(propertyRefernce1, propertyName); 

    Expression conversion = Expression.Convert(propertyReference2, typeof(object)); 
    Expression<Func<T, object>> currentExpression = Expression.Lambda<Func<T, object>>(conversion, new[] { parameter }); 
    return currentExpression; 

}