LINQ to entities - où..dans la clause avec plusieurs colonnes
Je suis en train d'interroger les données du formulaire avec LINQ-to-EF:
class Location {
string Country;
string City;
string Address;
…
}
par la recherche d'un lieu par le tuple (Pays, Ville, Adresse). J'ai essayé
var keys = new[] {
new {Country=…, City=…, Address=…},
…
}
var result = from loc in Location
where keys.Contains(new {
Country=loc.Country,
City=loc.City,
Address=loc.Address
}
mais LINQ ne veut pas accepter un type anonyme (ce que je comprends est la manière d'exprimer les tuples dans LINQ) en tant que paramètre à Contains().
Est-il un "gentil" la façon de l'exprimer dans LINQ, tout en étant en mesure d'exécuter la requête sur la base de données? Alternativement, si je viens de parcourir les touches et de l'Union()-ed les requêtes, ce serait mauvais pour la performance?
OriginalL'auteur millimoose | 2011-08-02
Vous devez vous connecter pour publier un commentaire.
Comment sur:
Mise à JOUR
Malheureusement EF jette NotSupportedException-dessus, ce qui disqualifie cette réponse si vous avez besoin de l'exécution de la requête sur DB côté.
Mise à JOUR 2
Essayé toutes sortes de jointures à l'aide des classes personnalisées et les Tuples - aucun ne fonctionne. Quels volumes de données parlons-nous? Si c'est rien de trop gros, vous pouvez soit en processus client-côté (pratique) ou de l'utilisation des syndicats (si pas plus rapide, moins de données est transmis).
Je me suis mise à l'essai dès maintenant pour voir si EF comprend que. Un autre ORM-je utiliser ferait l'affaire.
Je vais accepter cela comme un détail", cela ne semble pas être possible dans LINQ-to-EF" réponse. Le volume de données dans mon cas n'est pas élevé, donc je suis allé avec
Union()
-ment les requêtes (parce que dynamiquement la construction d'un prédicat dans LINQ est douloureux), et en croisant les doigts que SQL Server peut comprendre c'est tous les hits contre le même index.OriginalL'auteur Jacek Gorgoń
Bien que je ne pouvais pas obtenir @YvesDarmaillac du code du travail, il m'a indiqué cette solution.
Vous pouvez créer une expression, puis ajouter chaque état séparément. Pour ce faire, vous pouvez utiliser l'Universel PredicateBuilder (de la source à la fin).
Voici mon code:
Une chose à garder de, bien que, est que le filtre de la liste (le
keys
variable dans cet exemple) ne peut pas être trop grande, ou vous pouvez joindre les paramètres de limite, avec une exception comme ceci:Donc, dans cet exemple (avec trois paramètres par ligne), vous ne pouvez pas avoir plus de 700 Emplacements de filtre.
À l'aide de deux éléments de filtre, il va générer des 6 paramètres lors de la finale de SQL. Le SQL généré va ressembler à ci-dessous (mise en forme pour être plus clair):
Remarquez comment les initiales "false" l'expression est correctement ignorés et ne sont pas inclus dans la version finale de SQL par EntityFramework.
Enfin, voici le code pour le Universel PredicateBuilder, pour l'enregistrement.
OriginalL'auteur Marcos Dimitrio
Ma solution est de construire une nouvelle méthode d'extension WhereOr qui utilisent un ExpressionVisitor de construire la requête :
La suivante génère propre code sql exécutées sur la base de données :
J'ai essayé à l'aide de votre extension, mais
ICle
est pas défini. Pouvez-vous comprendre la définition deICle
?OriginalL'auteur Yves Darmaillac
devra être:
Je suis plussing cette réponse, la seule chose qui manque est l'sélectionnez la ligne et la fin de la requête.
OriginalL'auteur Chris Snowden
Il y a un EF extension existe, qui a été conçu pour très similaire. Il est EntityFrameworkCore.MemoryJoin (nom pourrait être déroutant, mais il prend en charge les EF6 et EF de Base). Comme indiqué dans l'auteur l'article il modifie SQL de la requête transmise au serveur et l'injecte VALEURS de la construction avec des données à partir de votre liste locale. Et la requête est exécutée sur le serveur de base de données.
Donc pour votre cas d'utilisation peut être comme cette
OriginalL'auteur Tony
Avez-vous essayé juste en utilisant le n-uplet de classe?
OriginalL'auteur sellmeadog
Si vous n'allez pas avoir besoin de beaucoup de combinaisons de touches, vous pouvez simplement ajouter un
LocationKey
propriété de vos données. Pour éviter de perdre beaucoup de stockage, peut-être rendre le code de hachage de la combinaison des propriétés.Ensuite interroger sur auront simplement une condition sur
LocationKey
. Enfin, dans le côté client filtrer les résultats à la baisse des entités qui ont le même hash, mais pas au même endroit.Il ressemblerait à quelque chose comme:
Alors simplement interroger sur la LocationKey propriété.
Pas idéal, mais cela devrait fonctionner.
OriginalL'auteur Ran
Je ne pense pas que qui va travailler pour vous depuis quand vous êtes newing un objet dans le
Contains
méthode qu'il va créer un nouvel objet à chaque fois. Puisque ces objets sont anonymes, la façon dont ils seront comparés sont contre leur référence qui sera différent pour chaque objet.Aussi, regardez Jacek réponse.
utilise le comparateur d'égalité, ce qui, pour les types anonymes utilise la propriété à l'égalité, ce n'est pas la question.
Vous avez entièrement raison. Mais est @Jacek solution vous aider?
OriginalL'auteur Tomas Jansson
Donner à ceci un essai.
OriginalL'auteur AD.Net
je pense que la bonne façon de le faire est
Il semble unoptimized mais la requête fournisseur de sortir et de faire de l'optimisation quand il transforme la requête sql. Lors de l'utilisation de n-uplets ou d'autres classes, à la requête du fournisseur ne sait pas comment faire pour les transformer en sql et que ce qui cause la NotSupportedException
-edit-
Si vous avez plusieurs tuples je pense que vous avez à boucle à travers eux tous et ne la requête ci-dessus pour chacun d'eux. encore une fois, cela peut sembler underoptimized, mais la requête pour retriving tous les sites dans une seule requête serait probablement jusqu'à la fin étant assez longue:
Le moyen le plus rapide de le faire est probablement de faire les requêtes simples, mais de les envoyer qu'un seul script sql et l'utilisation de plusieurs jeux de résultats pour effectivement obtenir chaque valeur. Je ne suis pas sûr que vous pouvez obtenir EF de le faire bien.
or
approche serait encore plus longue, mais on peut le court requête dans une déclaration préparée à l'avance et il serait de ce fait plus rapide. je ne sais pas si tout cela est pris en charge par EF siOriginalL'auteur aL3891
Je voudrais remplacer Contient (qui est une méthode spécifique pour les listes et les tableaux) avec l'ensemble de la IEnumerable une méthode d'extension:
Cela peut aussi être écrite:
OriginalL'auteur Evren Kuzucuoglu