Existe-t-il un moyen d'utiliser la méthode CompiledQuery.Compile pour compiler l'expression associée à un IQueryable? Actuellement, j'ai un IQueryable avec un très grand arbre d'expression derrière lui. L'IQueryable a été construit en utilisant plusieurs méthodes qui fournissent chacune des composants. Par exemple, deux méthodes peuvent renvoyer IQueryables qui sont ensuite jointes dans un tiers. Pour cette raison, je ne peux pas définir explicitement l'expression entière dans l'appel de méthode compile().Compiler des requêtes Linq vers SQL à partir d'un IQueryable non trivial
J'espérais passer l'expression dans la méthode de compilation sous la forme someIQueryable.Expression, mais cette expression n'est pas dans la forme requise par la méthode de compilation. Si je tente de contourner ce problème en mettant la requête directement dans la méthode de compilation, par exemple:
var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(dc => dc.getUsers());
var bar = foo(this);
où je fais le formulaire d'appel dans un datacontext, je reçois une erreur disant que « getUsers ne sont pas mises en correspondance comme stocké procédure ou fonction définie par l'utilisateur ". Encore une fois, je ne peux pas simplement copier le contenu de la méthode getUsers à l'endroit où je fais l'appel de compilation car il utilise à son tour d'autres méthodes.
Existe-t-il un moyen de transmettre l'expression sur le IQueryable retourné de "getUsers" dans la méthode Compile?
Mise à jour J'ai essayé de forcer ma volonté sur le système avec le code suivant:
var phony = Expression.Lambda<Func<DataContext, IQueryable<User>>>(
getUsers().Expression, Expression.Parameter(typeof(DataContext), "dc"));
Func<DataContext, IQueryable<User>> wishful = CompiledQuery.Compile<DataContext, IQueryable<User>>(phony);
var foo = wishful(this);
foo finit par être:
{System.Data.Linq.SqlClient.SqlProvider + OneTimeEnumerable `1 [Model.Entities.User]}
Je n'ai pas la possibilité de voir les résultats dans foo, car au lieu d'offrir d'étendre les résultats et d'exécuter la requête, je ne vois que le message" Operation coul d déstabilise l'exécution ". J'ai juste besoin de trouver un moyen pour que la chaîne sql ne soit générée qu'une seule fois et utilisée comme commande paramétrée sur les requêtes suivantes, je peux le faire manuellement en utilisant la méthode GetCommand sur le contexte de données, mais je dois explicitement définir tous les paramètres et faire moi-même le mappage des objets, qui est quelques centaines de lignes de code étant donné la complexité de cette requête particulière.
Mise à jour
John Rusk a fourni les informations les plus utiles, alors je lui ai accordé la victoire sur celui-ci. Cependant, quelques ajustements supplémentaires ont été nécessaires et il y avait quelques autres problèmes que j'ai rencontrés en cours de route, alors j'ai pensé que j'allais «élargir» sur la réponse. Tout d'abord, l'erreur 'Operation could destalization the runtime' n'était pas due à la compilation de l'expression, c'était en fait à cause d'une coulée profonde dans l'arbre d'expression. Dans certains endroits, j'avais besoin d'appeler la méthode .Cast<T>()
pour lancer des objets, même s'ils étaient du bon type. Sans entrer dans trop de détails, cela était essentiellement nécessaire lorsque plusieurs expressions étaient combinées dans un seul arbre et que chaque branche pouvait renvoyer un type différent, qui étaient chacun le sous-type d'une classe commune. Après avoir résolu le problème de déstabilisation, je suis revenu au problème de compilation. La solution d'expansion de John était presque là. Il a cherché des expressions d'appel de méthode dans l'arbre et a tenté de les résoudre à l'expression sous-jacente que cette méthode retournerait habituellement. Mes références aux expressions n'étaient pas fournies par les appels de méthodes, mais plutôt par les propriétés.Donc, je devais modifier le visiteur d'expression qui effectue l'expansion pour inclure ces types:
protected override Expression VisitMemberAccess(MemberExpression m) {
if(m.Method.DeclaringType == typeof(ExpressionExtensions)) {
return new ExpressionExpander().Visit((Expression)(((System.Reflection.PropertyInfo)m.Member).GetValue(null, null)));
}
return base.VisitMemberAccess(m);
}
Cette méthode ne peut pas être appropriée dans tous les cas, mais il devrait aider toute personne qui se trouve dans la même situation.
Pouvez-vous s'il vous plaît fournir plus de détails sur la façon dont vous avez réglé ce qui précède? Signification Je peux voir le code que vous avez mis dans la mise à jour mais où le mettre et il ne compile pas - "m.Method.DeclaringType" ne fait pas partie de MemberExpression et ExpressionExtensions n'existe pas. –
J'essaie de faire quelque chose de similaire avec la manipulation de l'arbre d'expression, et j'ai quelques questions concernant l'implémentation ci-dessus. Où sont définies ExpressionExpander et ExpressionExtensions? Pour autant que je puisse voir, ils ne font pas partie de LinqKit. Peut-être qu'ils faisaient partie d'une version plus ancienne? – Mel
En effet, il est très ennuyeux que l'échantillon de code soit incomplet. ExpressionExtensions est probablement sa propre classe qui remplace VisitMemberAccess, et m.Method.DeclaringType est probablement supposé être m.Member.DeclaringType. Mais le vrai problème est. GetValue (null, null) ne fonctionne tout simplement pas. – Charles