Я столкнулся с проблемой с сеткой ExtJS, где я включил удаленную фильтрацию, сортировку и группировку.Код структуры Entity по выражению
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 на лету, которая будет использоваться в хранилище шаблона, а следовательно, и Entity Framework. Этот скрипт хорошо работает для типов с недействительными значениями, но он дает ошибку выше, когда сортируются свойства NULL.
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;
Проблема здесь, вероятно, в том, что кастинг между объектом и типом с нулевым значением. Мне нужно будет убрать в выражении тип nullable.
Я думал о двух вариантов здесь:
1) Используйте какое-то универсальный метод для определения типа свойства вместо того, чтобы использовать тип объекта
2) ЯЩИК обнуляемого свойства, поэтому он может быть литым к объекту.
Я думаю, что вариант 2 является самым легким, но я как бы застрял здесь.
Update:
Я до сих пор не нашел решение для этого, но у меня есть обходной путь, пока я не решил эту проблему. Теперь ключ сортировки больше не является объектом, а является универсальным типом. Этот сценарий всегда будет работать, потому что нет никакого бокса происходит больше:
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);
}
Это работает, но, на мой взгляд, оно не очень масштабируемо. Я не вижу никаких простых или симпатичных исправлений здесь, чтобы динамически передавать тип методу сортировки. Любые предложения по этому вопросу?
Не могли бы вы выслать полный код, чтобы воспроизвести эту проблему? –
Я обновил свой вопрос с новой информацией. – hbulens