Entity Framework: LINQ to Entities ne prend en charge que la conversion des types primitifs de modèle de données Entity

entity-framework primitive-types

Question

J'ai écrit une méthode pour permettre à une expression d'être passée dans la clause orderby, mais j'ai rencontré ce problème.

Impossible de convertir le type 'System.DateTime' en 'System.IComparable'. LINQ to Entities ne prend en charge que la conversion des types primitifs Entity Data Model.

Fondamentalement, l'expression est la suivante:

Expression<Func<K, IComparable>> orderBy

Et est utilisé comme ceci:

SomeEntities.SomeTable
.Where
(
   whereClause
)
.Select
(
   selectClause
)
.OrderBy(orderBy)

L'idée est que je puisse utiliser un dictionnaire pour contenir des correspondances de chaînes avec des expressions telles que:

_possibleSortForForumItem.Add("CreateDate", item => item.CreateDate);

Ensuite, j'ai une méthode qui prend la chaîne de tri et renvoie l'expression si elle correspond à une clé du dictionnaire, sinon renvoie une valeur par défaut. (L'idée étant un moyen de contrôler ce qui peut être commandé par) Maintenant, cela fonctionne pour les propriétés String, mais jusqu'à présent pas pour datetime ou entier car je reçois le message d'erreur ci-dessus.

Pour autant que je comprenne (vaguement), le problème est que Entity Framework a besoin que ce soit un type primaire / EDM car il doit convertir le C # DateTime en quelque chose que la base de données peut gérer.

Existe-t-il un moyen de convertir l'heure de la date en un type primitif afin que cela fonctionne toujours?

Solution

La méthode pour obtenir la commande par méthode: (Recueillez une requête et renvoyez-la sous la forme "commandée")

private static Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>> GetMethodForSort(String sortBy)
{
  if (_methodForSort == null)
  {
    _methodForSort = new Dictionary<String, Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>>>();
    _methodForSort.Add(SortForumViewItemCreatedOn, item => item.OrderBy(innerItem => innerItem.CreatedOn));
    ...
  }

  Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>> orderMethod;

  if(String.IsNullOrEmpty(sortBy) || !_methodForSort.ContainsKey(sortBy))
  {
    orderMethod = _methodForSort["ForumName"];
  }
  else
  {
    orderMethod = _methodForSort[sortBy];
  }

  return orderMethod;
}

La signature de méthode pour la méthode de requête générique:

IList<K> GetListForGrid<T, K>(this ObjectQuery<T> query, ... Func<IQueryable<K>, IOrderedQueryable<K>> orderBy, ...)

Et l'utilisation de la méthode passée:

initialQuery = query
  .Where
  (
    somethingEqualsSomething
  )
  .Select
  (
    selectClause
  );

var orderedQuery = orderBy(initialQuery);

returnValue = orderedQuery
  .Skip(numberToShow * realPage)
  .Take(numberToShow)
  .ToList();

Réponse acceptée

Entity Framework rend cela difficile et je ne suis pas sûr qu'il existe un moyen de faire ce que vous voulez faire avec un seul type de valeur de retour (IComparable, objet, etc.). Vous pouvez envisager de retravailler votre conception dans un dictionnaire de valeurs nom-à- Func<IQueryable<K>, IOrderedQueryable<K>> :

_possibleSortForForumItem.Add("CreateDate", 
    query => query.OrderBy(item.CreateDate));

Et ensuite, l'appliquer comme ceci:

var orderedQuery = query.OrderBy(item => item.DefaultOrderColumn);

Func<IQueryable<K>, IOrderedQueryable<K>> assignOrderBy = null;

if (_possibleSortForForumItem.TryGetValue(orderColumnName, out assignOrderBy))
{
    orderedQuery = assignOrderBy(query);
}

Réponse populaire

Je sais que c'est vieux, mais je cherchais à faire exactement la même chose que l'OP et je ne voulais pas utiliser Func<IQueryable<T>, IOrderedQueryable<T>> dans mon dictionnaire. Principalement parce que je devrais mettre en place un OrderBy et OrderByDescending .

J'ai fini par créer une méthode d'extension pour IQueryable appelée ObjectSort qui va simplement vérifier le type de retour de l'expression, puis créer un nouveau lambda en utilisant ce type pour que LINQ to Entities ne flippe pas.

Je ne suis pas sûr qu'il s'agisse d'une bonne solution ou non, mais l'exemple ci-dessous fonctionne pour DateTime et int . J'espère donc qu'il pourra vous donner quelques idées si vous souhaitez accomplir quelque chose de similaire!

public static IOrderedQueryable<T> ObjectSort<T>(this IQueryable<T> entities, Expression<Func<T, object>> expression, SortOrder order = SortOrder.Ascending)
{
    var unaryExpression = expression.Body as UnaryExpression;
    if (unaryExpression != null)
    {
        var propertyExpression = (MemberExpression)unaryExpression.Operand;
        var parameters = expression.Parameters;

        if (propertyExpression.Type == typeof(DateTime))
        {
            var newExpression = Expression.Lambda<Func<T, DateTime>>(propertyExpression, parameters);
            return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
        }

        if (propertyExpression.Type == typeof(int))
        {
            var newExpression = Expression.Lambda<Func<T, int>>(propertyExpression, parameters);
            return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression);
        }

        throw new NotSupportedException("Object type resolution not implemented for this type");
    }
    return entities.OrderBy(expression);
}


Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow