2015-09-29 2 views
1

Я столкнулся с проблемой с сеткой 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); 
    } 

Это работает, но, на мой взгляд, оно не очень масштабируемо. Я не вижу никаких простых или симпатичных исправлений здесь, чтобы динамически передавать тип методу сортировки. Любые предложения по этому вопросу?

+0

Не могли бы вы выслать полный код, чтобы воспроизвести эту проблему? –

+0

Я обновил свой вопрос с новой информацией. – hbulens

ответ

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; 
Смежные вопросы