6
votes

Rechercher à travers la clause de Linq, en utilisant des propriétés dynamiques

J'essaie essentiellement de construire une requête et je ne sais pas pourquoi Microsoft a rendu cela si difficile dans le cadre d'entité et Linq. J'ai différentes chaînes de paramètres. Donc, si vous voyez une variable, supposez que c'est une chaîne passée de quelque part.

.Where(x => x.GetType().GetProperty(searchfield).GetValue(x, null).ToList().Contains(search))


11 commentaires

Avez-vous essayé ma réponse dans votre autre question? Stackoverflow.com/Questtions/11992717/...


Avez-vous essayé de faire la même chose sans ef, dans des objets de linq ordinaires?


Mais pourquoi EF empêcherait-il quelque chose qui peut être fait dans Linq-to-Objects? Je pensais que EF était supposé être plus avancé et rendre les choses plus faciles à interroger.


@Dexter Vous avez déjà été répondu que: EF permet uniquement d'expressions pouvant être traduites à SQL. Celui-ci ne peut pas être (ou la traduction est trop difficile). EF est pas censé être plus "avancé" que linq-to-objets, c'est une autre mise en œuvre avec d'autres objectifs.


Compris mais je ne vois pas ce qui est difficile avec la traduction: A.String.Contains (). Cela fonctionne bien lorsque vous connaissez la chaîne et écrivez-la comme une constante A.Field.Contains (). Pourquoi est-il soudain difficile lorsque vous ne savez pas quelle variable de chaîne sera?


Parce que ce n'est pas "variable" ou "constante", c'est une référence de propriété. Il me semble que vous ne comprenez pas que l'expression de Lambda dans votre code n'est qu'un raccourci pour construire AST. Les concepteurs de langue ont décidé de ne pas mettre en œuvre des références de biens dynamiques dans ce raccourci (principalement parce que c # est - principalement - une langue typée statiquement).


N'est toujours pas de sens que cela ne fonctionnera pas avec des préférences dynamiques. Il n'y a pas de conséquences négatives pour permettre aux gens de saisir de manière dynamique quels domaines ils veulent de leur base de données, c'est idiot. Ils devraient fournir un moyen simple de convertir ces datatypes à tout ce qu'ils veulent.


Parce qu'il n'ya aucun moyen d'exprimer une référence de propriété dynamique dans C #. Et en ce qui concerne "de type dynamique de quels champs": je répéterais une fois de plus: il y a déjà un mécanisme d'accès dynamique de données dans .NET, il basse sur datatable s et Dataset s et il fonctionne . EF est un outil pour ceux qui veulent des références statiques et Vérification statique .


Comme quoi, exactement? Rien n'est mis en œuvre par défaut. Vous ne demandez pas simplement si et comment quelque chose peut être fait, mais en réduisant l'absence de mise en œuvre. Si vous pensez que c'est un tel avertisseur d'ajouter un support pour cela, vous devriez ajouter ce support vous-même.


@Jonhanna Oui, il devrait être mis en œuvre comme dans une bibliothèque moderne Orm. C'est absolument une certitude. Et oui, je vous demande comment le faire, c'est pourquoi j'ai fait ce post. Je ne comprends pas ce que vous essayez de dire, il n'y avait certainement pas d'allégement non plus, de sorte que vos implications sont immatures et inutiles.


Votre déclaration que la SP a rendu difficile. Ils ne l'ont pas fait difficile, ils n'ont pas réussi à faciliter la tâche, ce qui est très différent.


4 Réponses :


5
votes

Cela devrait être incroyablement facile et simple pour une langue moderne

Non, cela ne devrait pas si cela va contre ce paradigme de langue. Le cadre LINQ et entité (ainsi que tout autre orje décent) sont précisés pour éviter ce que vous essayez d'accomplir: des requêtes non typées et non compilates. Donc, fondamentalement, vous forcez la cheville carrée dans un trou rond.

Vous pouvez toujours jeter un coup d'œil à dynamique linq .


14 commentaires

Les langues / cadres ne doivent pas être conçus pour être des baby-sitters pour vous empêcher de faire des problèmes de sécurité. Ils doivent être conçus pour vous donner la pleine puissance nécessaire pour créer des instances dynamiques afin de ne pas avoir à taper une montagne de code ou d'installer une énorme nouvelle bibliothèque pour faire quelque chose de très simple, comme générer une table dynamique avec différents champs de la Base de données, en fonction de la page que vous chargez. Je n'utilise pas Dynamic Linq et je ne pense pas que j'aurais besoin de si c'est le seul moyen. Il est surchargé pour ce que je dois faire, ce que je pense peut être accompli avec une réflexion.


En outre, il n'y a aucune raison pour laquelle un concepteur-cadre devrait vous permettre de taper "où (x => x.field1.contains (recherche))" mais ne vous permet pas de pouvoir faire "où (x => x.gepropertybyname (SearchField ) .Contains (recherche)) "--- Un cadre intelligemment conçu permettrait que si vous ne voyez pas un problème que je ne vois pas. Sinon, il est plus facile pour moi de saisir simplement un cas d'interrupteur, pour chaque nom de champ, plutôt que d'installer une bibliothèque.


LINQ Permet Vous de le faire. Ef pas.


En ce qui concerne votre premier commentaire: pourquoi utiliser un outil typé fort où vous avez évidemment besoin de dynamique? Pourquoi ne pouvez-vous pas simplement utiliser datatable ?


Dexter, Linq interprète l'argument à SELECT comme arborescence d'expression et traduit cet arborescence d'expression à SQL. Il y a un équivalent SQL à contient , mais pas sur getPropertybyname . Résoudre le problème général de la conversion de code de réflexion comme celui-ci est probablement insuffisant.


Si c'était à moi, j'utiliserais Python et Django et j'étais fait avec elle. Mais oui je m'améliore sur un projet ASP.NET. Datatable était ce que j'utilisais auparavant, mais je veux maintenant le créer de manière dynamique parce que le jeu de données perd de nombreuses choses et ne fonctionne pas bien avec l'entitéFramework. Par conséquent, je préfère le faire de zéro.


@Thomsmith pour que vous disiez ce que je veux faire est impossible, sauf si je connais le champ que l'utilisateur souhaite rechercher.


DataTable Ne fonctionne pas avec EF du tout (il me semble que vous n'obtenez pas ce que EF est pour ). Quelles "choses" fait datatable perdent?


Donc, ce que je ferais, est-ce que je créerais ma requête spécifique avec EF. Créez ensuite un objet de jeu de données et liez cela. Et ainsi, quand quelqu'un trie quelque chose, cela fonctionne - sauf quand ils vont à la page suivante, il perd le tri car il se renseigne. Il semble qu'il est temps de le construire à partir de zéro et de mettre mes propres variables dans l'URL pour suivre la pagination. Oui, je suppose que EF est d'essayer de faire une interrogation plus facile, avec le chargement paresseux, etc., mais jusqu'à présent, il s'est avéré aussi difficile.


Vous devez garder vos informations de tri entre les pages. C'est tout à fait un autre problème (et facilement solvable).


@Dexter: Ce n'est pas impossible, il suffit de construire un arbre d'expression.


@Thomsmith Comment puis-je construire un arbre d'expression?


@Thomsmith ou remplacer iquéryable avec iEnumerable et utilisez des délégués avec n'importe quelle logique qu'il veut à l'intérieur.


@Dexter: J'ai ajouté un exemple à ma réponse ci-dessous. Cela devrait être principalement du code de travail.



0
votes

10 commentaires

Oui une bonne réponse, mais je ne veux pas énumérer 10 cas de commutation, il devrait y avoir un moyen de le faire de manière dynamique.


Mais pourquoi se soucier de la nature dynamique de celui-ci? Oui, peut-être qu'il devrait être un moyen, mais changez-vous vraiment les propriétés sur vos entités qui souvent? J'ai vu faire le commutateur et être fait avec elle. EF ne vaut jamais ce genre de stress!


Vous avez raison, mais cela change parfois. Et il sera utilisé sur beaucoup de classes différentes avec des propriétés différentes. Je veux un système dynamique pour que je puisse passer dans un tableau de champs que je souhaite de la base de données et c'est tout.


@Dexter une fois de plus: si vous voulez "système dynamique", utilisez datatable s. Ils sont juste la chose pour votre tâche.


J'utilisais des datatables, ça ne marche pas. Il faut une quantité d'effort de gargantues pour le faire de cette façon. Et vous êtes obligé d'utiliser ces stupides petites tags ASP partout partout qui ne vous donnent pas la capacité de personnaliser quoi que ce soit. Je ne vois pas pourquoi je ne peux pas utiliser EF et Linq et générer de manière dynamique mes tables et tapez les champs que je souhaite dans la base de données et saisissez comment les présenter. Pourquoi ce concept simple est-il si difficile à comprendre? Je suis aussi proche de frapper littéralement mes propres déclarations SQL et d'utiliser mes propres fonctions de construction de requêtes car apparemment LINQ et EF ne vous aident pas.


En fin de compte, il s'agit d'un code que supposait convertir mes relevés en requêtes String SQL, qui sont envoyées directement à MSSQL, comment puis-même saisir mes instructions SQL dans les procédures stockées de MSSQL, mais cela devient terriblement difficile et tâche déroutante avec les lambdas et d'autres objets déroutants en matière de Linq et d'EF?


@ SergrogoVTsev Ne pensez-vous pas que c'est un peu drôle que je dois taper 20 lignes de code pour quelque chose qui peut être effectué dans 1-2 lignes dans les procédures stockées MSSQL ou Python, ou PHP, ou même fortement dactylographié C ++, ou tout autre bibliothèque qui n'implique pas EF ou Linq?


@Dexter non, je ne le fais pas. Parce que comme je l'ai déjà dit, vous devez choisir un instrument pour votre tâche. Et vous ne pouvez pas utiliser EF et Linq et générer de manière dynamique mes tables », car EF est conçu pour fournir une typographie statique (la plupart des ormes). Lorsque vous avez besoin d'un accès dynamique de données, vous utilisez DataTable S (ou même DataReader s). Et il me semble que vous ne comprenez pas comment datatable fonctionne car il a rien à faire avec "stupide petites tags asp".


@SergrogOVTsev Objectif ORMS est de rendre les choses plus faciles et plus dynamiques, avec moins de codage. Pas l'inverse. Ce n'est certainement pas ce que devrait faire EF. C'est ce que Microsoft a choisi Microsoft comme meilleur moyen. J'ai utilisé des datates de temps, mais vous devez toujours utiliser EF pour ormer ou que vous seriez obligé d'utiliser des instructions SQL saisies à l'aide de SQLCLIPT, etc. Je ne vois pas pourquoi vous continuez à mentionner de sorte que ce n'est qu'un objet de conteneur.


@Dexter Vous dites toujours "dynamique" mais je ne pense pas comprendre ce que vous entendez par là.



2
votes

Vous devrez construire un arbre d'expression à passer au où code> méthode. Voici une adaptation lâche de certains code que j'ai couché sur: xxx pré>

qui générera une expression appropriée à utiliser comme paramètre sur où p> p>

EDIT: FYI, l'expression résultante ressemblera à quelque chose comme user => user.foo.fooo.contains (bar) code>. P>

EDIT: Pour trier, quelque chose comme ça (déchiré de mon Classe DynamicOrderList): P>

private IQueryable<T> OrderQuery<T>(IQueryable<T> query, OrderParameter orderBy)
{
    string orderMethodName = orderBy.Direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending";
    Type t = typeof(T);

    var param = Expression.Parameter(t, "user");
    var property = t.GetProperty(orderBy.Attribute);

    return query.Provider.CreateQuery<T>(
        Expression.Call(
            typeof(Queryable),
            orderMethodName,
            new Type[] { t, typeof(string) },
            query.Expression,
            Expression.Quote(
                Expression.Lambda(
                    Expression.Property(param, property),
                    param))
        ));
}


1 commentaires

Oui excellent cela fonctionne bien. Mais je ne sais pas comment le changer pour Orderby et OrderbyDescendant basé sur un nom de propriété string?



9
votes

Ce n'est pas trivial, mais je crois que cela peut être fait. Ce qui suit n'a pas été testé. Le code est emprunté à ici .

Créez une méthode d'assistant quelque part comme xxx

l'utiliser comme xxx

Mise à jour

Au fur et à mesure, vous pouvez créer des méthodes d'extension pour fournir une syntaxe plus propre. Créez les méthodes suivantes dans une classe statique quelque part: xxx

alors vous pouvez les appeler comme: xxx


11 commentaires

Je devrais ajouter que je suis d'accord avec d'autres affiches en ce que c'est un peu comme farcir une cheville carrée dans un trou rond. Vous feriez mieux d'utiliser une bibliothèque comme Dynamic Linq, il a été construit pour faire exactement ce que vous êtes après.


Comment ça se passe? La bibliothèque Dynamic Linq est énorme. C'est une solution rapide très compacte pour plus particulièrement cette situation, car tout ce que j'écris n'est pas "string-to-linq-to-ef"


L'un des principaux avantages de LINQ-TO-EF, car je vois qu'il est de fournir une enveloppe fortement typée autour de votre code d'accès aux données. Avec une solution comme celle-ci, vous perdez de nombreux avantages fournis par cette frappe forte.


Oui ça marche génial. Le seul problème est que je ne sais pas comment convertir cette fonction à utiliser pour Orderby et OrderbyDescendant, comme ceux qui ne fonctionnent pas non plus avec des propriétés à chaîne variable.


Je ne vois pas les avantages dans une frappe forte dans cette situation. Je veux juste que cela fonctionne sans les tracas des types, je préférerais si cela vient de convertir toutes les valeurs en chaîne à la sortie sur le site Web.


Nevermind, je l'ai compris ... Utilisateurs = this.entities.Utilisateurs.Lès (getContainSexpression (Searchfield, recherche)) .Orderbydescendants (x => order_by) .skip (convert.toint32 (limite_begin)) .take ( Convert.toint32 (limit_end)) .tolist ();


J'ai mis à jour la réponse avec la façon de résoudre le problème de la commande. Je peux certainement comprendre vouloir vouloir une solution «fonctionne simplement».


Ouais tu l'as eu. Merci. Je ne sais pas pourquoi tout le monde veut que je puisse installer une nouvelle bibliothèque gigantesque, que je devrais apprendre et comprendre, pour quelque chose de si simple. Je ne sais pas pourquoi par "x => order_by" a tout simplement fonctionné, je n'ai pas besoin de votre fonction "getPropertyexpression" (encore).


J'ai essayé de modifier votre 2e Fonction, mais rencontrez des erreurs en utilisant le tri de DateTime. Dit Parameterexpression de type 'DateTime' ne peut pas être utilisé pour le paramètre délégué du type USERTABLE. EXPRESSION STATIQUE PUBLIQUE > GETPROPERTYEXPRESSION (String NomName) {var paramètreExp = expression.paramètre (typeof (t), "Type"); var paramètreeexp2 = expression.paramètre (typeof (tykey), "type"); var exp = expression.property (paramètreeexp, propriétéName); expression retour.Lambda > (exp, paramètreeexp2); }


J'ai mis à jour la réponse fixant le problème dans la méthode getPropertyExpression


Bonjour, je suis confronté à un problème lorsque j'utilise "où la chaîne contient" avec des propriétés de type de données GUID. Comment gérer ceux-ci?