实体框架的导航属性在为空之后为空
问题描述:
我使用以下代码通过表达式转换顺序,因此也可以排序可以为空的列。实体框架的导航属性在为空之后为空
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异常。
我知道订购导航属性不起作用,但这不是问题。按“常规”属性排序会导致问题。
对这个有什么想法?
答
原来这个问题并不像我想的那么复杂。问题是我创建了错误的表达式树。您可以嵌套表达式,以便您可以导航到属性的属性。
下面的解决方案应该解释(这不是我实际上是如何解决这个问题,但它应该清楚):
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;
}
让从这里开始。按表达式排序不能像谓词那样组合,但需要与'OrderBy/ThenBy'链接。这意味着你需要一种不同的方法 - 'IQueryable'扩展方法而不是表达式返回方法。当按表达式应用顺序时,不需要将它们转换为“object”类型。 –
我同意你的第一个陈述,但你的第二种方法似乎并不正确。您需要为排序定义一个TKey类型。因为我的场景必须能够接受任何类型,所以我只使用了对象。但是这两个陈述都不适合我的问题。我已经为这个问题创建了一个解决方法,但我仍然好奇这是否可能。 – hbulens
问题在于'Expression>'是不一样的(不能转换成)'Expression >'。另外,当你使用像这样的表达式时,得到的表达式体不是成员访问,而是可以从上面得到的,但是转换。为什么你认为'OrderBy/ThenBy'声明了第二个泛型参数,如果它很容易忽略它。 –