我遇到了ExtJS网格的问题,我启用了远程过滤,排序和分组。
System.NotSupportedException: Unable to cast the type 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ValidateAndAdjustCastTypes(TypeUsage toType, TypeUsage fromType, Type toClrType, Type fromClrType)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.GetCastTargetType(TypeUsage fromType, Type toClrType, Type fromClrType, Boolean preserveCastForDateTime)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.CreateCastExpression(DbExpression source, Type toClrType, Type fromClrType)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ConvertTranslator.TranslateUnary(ExpressionConverter parent, UnaryExpression unary, DbExpression operand)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.UnaryTranslator.TypedTranslate(ExpressionConverter parent, UnaryExpression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.UnarySequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.UnarySequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SelectTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
bij Systm.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
bij System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.Convert()
bij System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
bij System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassc.<GetResultsAsync>b__a()
bij System.Data.Entity.Core.Objects.ObjectContext.<ExecuteInTransactionAsync>d__3d`1.MoveNext()
下面的代码示例转换输入模型(指示方向和属性名称的字符串属性)并动态生成LINQ脚本,该脚本将用于存储库模式,因此也将用于实体框架。此脚本适用于非可空类型,但在对可空属性进行排序时会出现上述错误。
Expression<Func<Task, object>> orderByClause = default(Expression<Func<Task, object>>);
if (sortObjects != null)
{
foreach (Order sortObject in sortObjects)
{
// Get type and property of type
ParameterExpression parameter = Expression.Parameter(typeof(Task), "x");
PropertyInfo property = typeof(Task).GetProperty(sortObject.Property);
// Create left hand side of the lambda: x => x.PROPERTY
MemberExpression propertyAccess = Expression.Property(parameter, property);
LambdaExpression orderByExp = Expression.Lambda(propertyAccess, parameter);
// Create expression from lambda
MemberExpression orderByExpression = Expression.Property(parameter, sortObject.Property);
Expression conversion = Expression.Convert(orderByExpression, typeof(object));
Expression<Func<Task,object>> lambda = Expression.Lambda<Func<Task, object>>(conversion, parameter);
if (orderByClause == default(Expression<Func<Task, object>>))
{
orderByClause = lambda;
}
else
{
InvocationExpression invokedExpr = Expression.Invoke(lambda, orderByClause.Parameters.Cast<Expression>());
orderByClause = Expression.Lambda<Func<Task, object>>(Expression.AndAlso(orderByClause.Body, invokedExpr), orderByClause.Parameters);
}
}
}
return orderByClause;
这里的问题可能是对象和可空类型之间的转换。我需要能够在表达式中包含可空类型。
我在考虑两种选择:
1)使用某种通用方法来定义属性类型,而不是使用对象类型
2)装入可以为空的属性,以便它可以被转换为一个对象。
我认为选项2是最简单的,但是我有点困在这里。
更新
我仍然没有为此找到解决方案,但在解决此问题之前,我有一个解决方法。现在排序键不再是一个对象,而是一个泛型类型。此场景将始终有效,因为不再发生任何拳击:
protected virtual Expression<Func<T, TKey>> GetSorting<TKey>(string ordering)
{
IEnumerable<Order> sortObjects = string.IsNullOrEmpty(ordering) ? null : JsonConvert.DeserializeObject<IEnumerable<Order>>(ordering);
Expression<Func<T, TKey>> orderByClause = default(Expression<Func<T, TKey>>);
if (sortObjects != null)
{
foreach (Order sortObject in sortObjects)
{
// Get type and property of type
ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
PropertyInfo property = typeof(T).GetProperty(sortObject.Property);
// Create left hand side of the lambda: x => x.PROPERTY
MemberExpression propertyAccess = !sortObject.ComplexType ? Expression.Property(parameter, property) : Expression.PropertyOrField(Expression.Property(parameter, property), sortObject.ComplexTypeProperty);
MemberExpression orderByExpression = !sortObject.ComplexType ? Expression.Property(parameter, sortObject.Property) : Expression.PropertyOrField(Expression.Property(parameter, property), sortObject.ComplexTypeProperty);
// Create expression from lambda
Expression<Func<T, TKey>> lambda = Expression.Lambda<Func<T, TKey>>(orderByExpression, parameter);
if (orderByClause == default(Expression<Func<T, TKey>>))
{
orderByClause = lambda;
}
else
{
InvocationExpression invokedExpr = Expression.Invoke(lambda, orderByClause.Parameters.Cast<Expression>());
orderByClause = Expression.Lambda<Func<T, TKey>>(Expression.AndAlso(orderByClause.Body, invokedExpr), orderByClause.Parameters);
}
}
}
return orderByClause;
}
这是我如何称呼这种方法。根据用户的输入,我确定正在对哪个属性进行排序。使用反射,我检索它的类型,然后我将其作为排序方法的类型传递。
switch (propertyType)
{
case "Int32":
Expression<Func<Resource, int?>> orderIntExpression = this.GetSorting<int?>(ordering);
return await this.GetResources<int?>(page, pageSize, orderIntExpression, base.IsAscending(ordering), selector, mergedQuery);
default:
Expression<Func<Resource, object>> orderDefaultExpression = this.GetSorting<object>(ordering);
return await this.GetResources<object>(page, pageSize, orderDefaultExpression, base.IsAscending(ordering), selector, mergedQuery);
}
这有效,但在我看来它不具备可扩展性。我没有在这里看到任何简单或漂亮的修复,以动态地将类型传递给排序方法。关于此事的任何建议?
答案 0 :(得分:0)
经过大量的反复试验后,我通过编写下面的代码救出了自己。它尚未完成,但这允许对可空类型进行排序和分组。
Expression<Func<T, dynamic>> sortExpression = default(Expression<Func<T, dynamic>>);
IEnumerable<Order> sortObjects = string.IsNullOrEmpty(ordering) ? null : JsonConvert.DeserializeObject<IEnumerable<Order>>(ordering);
if (sortObjects != null)
{
foreach (Order sortObject in sortObjects)
{
Type type = typeof(T);
ParameterExpression parameter = Expression.Parameter(type, "x");
MemberExpression propertyReference = Expression.Property(parameter, sortObject.Property);
Expression conversion = Expression.Convert(propertyReference, typeof(object));
sortExpression = Expression.Lambda<Func<T, dynamic>>(conversion, new[] { parameter });
break;
}
}
return sortExpression;