Créer LINQ to entities OrderBy expression à la volée
J'essaie d'ajouter de la orderby expression à la volée. Mais lorsque la requête ci-dessous est exécutée j'obtiens l'exception suivante:
Système.NotSupportedException: Impossible
pour créer une valeur constante de type
Fermeture type". Seuls les types primitifs
("comme Int32, String et Guid')
sont pris en charge dans ce contexte.
La chose étrange est, je suis à la requête exactement ces types de primitives.
string sortBy = HttpContext.Current.Request.QueryString["sidx"];
ParameterExpression prm = Expression.Parameter(typeof(buskerPosting), "posting");
Expression orderByProperty = Expression.Property(prm, sortBy);
//get the paged records
IQueryable<PostingListItemDto> query =
(from posting in be.buskerPosting
where posting.buskerAccount.cmsMember.nodeId == m.Id
orderby orderByProperty
//orderby posting.Created
select new PostingListItemDto { Set = posting }).Skip<PostingListItemDto>((page - 1) * pageSize).Take<PostingListItemDto>(pageSize);
Espère que quelqu'un peut jeter un peu de lumière sur ce!
OriginalL'auteur AyKarsi | 2010-05-15
Vous devez vous connecter pour publier un commentaire.
Fondamentalement, vous ne pouvez pas utiliser les expressions de la requête comme ceci, en raison de la façon dont ils sont traduits. Cependant, vous peut faire explicitement avec les méthodes d'extension:
Le problème est d'obtenir le droit d'expression le type d'arbre - qui viendra dans un edit 🙂
EDIT: L'édition sera un peu retardée pour diverses raisons. Fondamentalement, vous pouvez avoir besoin d'appeler une méthode générique à l'aide de la réflexion, comme
Queryable.OrderBy
besoin d'un génériqueExpression<Func<TSource, TKey>>
et bien qu'il regarde comme vous le savez le source de type à la compilation, vous ne pouvez pas savoir le type de clé. Si vous ne sais qu'il sera toujours de la commande par le (dire) un int, vous pouvez utiliser:EDIT: Bon, il semble que j'ai eu le temps après tout. Voici un court exemple de l'appel
OrderBy
l'aide de la réflexion:Vous pouvez facilement refactoriser
CallOrderBy
dans une méthode d'extension (par exemple,OrderByProperty
) comme ceci:Votre code d'origine devient alors:
(Mes excuses pour la mise en forme impliquant des barres de défilement horizontale... je vais reformater plus tard, si quelqu'un se soucie. Ou vous pourriez le faire pour moi si vous avez assez de rep 😉
OrderBy
s'attendre à une expression lambda? Par exemple:Expression.Lambda<Func<T,U>>(orderByProperty, prm)
Oui, elle attend un
Expression<...>
- qui est pourquoi j'ai utiliséorderByExpression
plutôt queorderByProperty
. J'ai été en espérant que dans le reste du code, mais quelque chose est venu donc je ne serai pas en mesure de terminer à l'instant.De Grandes Choses! Merci Jon!
Génial! Sauvé ma journée.
OriginalL'auteur Jon Skeet
Je voulais partager ma mise en œuvre à l'aide de Jon réponse ci-dessus comme point de départ. Dans ce cas, plutôt que de tri par une propriété de chaîne de nom provenant de la couche de présentation (comme le titre de cette question n'est pas spécifique à ce sujet), je suis la création d'une Entité Cadre de la couche de données et vous souhaitez permettre à ses consommateurs à spécifier l'ordre par les propriétés les expressions lambda. I. E. Plutôt que de passer
"sidx"
, je voulais être en mesure d'utiliserp => p.sidx
. Je voulais aussi être en mesure de passer un nombre illimité d'ordre par les propriétés et être en mesure de spécifier l'ordre croissant ou décroissant.Bien ma méthode peut accepter une telle expression lambda comme type
Expression<Func<T, object>>
. Que laissez-moi l'appeler comme je veux, mais le problème est, Entity Framework ne peut pas traduire l'expression SQL à moins que le second paramètre générique est fortement typé. Le OrderBy méthode d'extension nécessite deux paramètres génériques: T - le type de la propriété appartient à, et TKey - le type de la propriété renvoie. Donc, la première étape a été de modifier Jon exemple, pour convertir une donnéeExpression<Func<T, object>>
à unExpression<Func<T, Tkey>>
(une fois que nous travaillons dans le cadre d'une requête, nous pouvons déterminer le typeTKey
):Comme je l'ai mentionné, je veux accepter un nombre illimité de commande par sélecteurs à clé et ont également la possibilité de spécifier l'ordre croissant ou décroissant direction donc j'ai fait une classe wrapper pour le
Expression<Func<T, object>>
j'ai nommé DynamicSortExpression:Puis j'ai mis à jour la méthode d'extension pour accueillir ce type et a créé une surcharge pour
OrderBy
qui reçoit unList<DynamicSortExpression<T>>
et les ajoute à la requête à l'aide de la méthode d'extension(s) un par un. Voici le résultat final:Maintenant, ma couche de données peut avoir une méthode comme
List<T> GetList(Expression<Func<T, bool>> where, params DynamicSortExpression<T>[] orderBy)
qui peut être appelée commeLa
RemoveConvert
méthode est quelque chose que j'ai tiré hors de la EntityFramework code source récursive de supprimer Convertir les appels à partir d'un MemberExpression:J'espère que c'est utile! Merci Jon!
OriginalL'auteur xr280xr