Type de soutien aux membres dans les requêtes LINQ-to-Entités?
J'ai un MVC3 projet à l'aide du modèle d'Entity Framework dans lequel j'ai marqué d'une classe comme ceci:
public partial class Product
{
public bool IsShipped
{
get { /* do stuff */ }
}
}
et que je veux l'utiliser dans une expression LINQ:
db.Products.Where(x => x.IsShipped).Select(...);
cependant, j'obtiens l'erreur suivante:
Système.NotSupportedException a été gérée par le code de l'utilisateur Message=La
type spécifié membre 'IsShipped" n'est pas pris en charge dans LINQ to entities.
Seulement les initialiseurs, les membres de l'entité et l'entité propriétés de navigation
sont pris en charge. Source=Système.Les données.Entité
J'ai cherché sur google mais rien trouvé de définitif sur cette utilisation, j'ai essayé:
public partial class Product
{
public bool IsShipped()
{
/* do stuff */
}
}
db.Products.Where(x => x.IsShipped()).Select(...);
mais puis-je obtenir:
Système.NotSupportedException a été gérée par le code de l'utilisateur Message=LINQ
à des Entités qui ne reconnaît pas la méthode Boolean IsShipped () "méthode",
et cette méthode ne peut pas être traduit dans un magasin d'expression.
Source=Système.Les données.Entité
il y a une fonctionnalité que je ne veux pas construire dans la requête LINQ lui-même... ce qui est une bonne façon de gérer cela?
* mise à jour *
Darin fait le point valide que ce qui est fait dans la mise en œuvre de IsShipped
aurait besoin d'être converti en une requête SQL et le compilateur n'a probablement pas savoir comment faire, donc la récupération de tous les objets en mémoire semble le seul choix (à moins qu'une requête directe à la base de données est faite). J'ai essayé comme ceci:
IEnumerable<Product> xp = db.Quizes
.ToList()
.Where(x => !x.IsShipped)
.Select(x => x.Component.Product);
mais il génère cette erreur:
Une relation multiplicité de violation de contrainte produite: Une
EntityReference peut pas avoir plus d'un objet, mais l'
requête a retourné plus d'un objet connexe. C'est un non-récupérables
erreur.
bien que curieusement, cela fonctionne:
IEnumerable<Product> xp = db.Quizes
.ToList()
.Where(x => x.Skill.Id == 3)
.Select(x => x.Component.Product);
pourquoi cela?
* mise à jour II *
désolé, cette dernière affirmation ne fonctionne pas non plus...
* mise à jour III *
Je suis à la clôture de cette question en faveur de la poursuite d'une solution comme suggéré ici pour aplatir ma logique dans une requête - la discussion se déplacer à ce nouveau post. La deuxième alternative, pour récupérer la totalité de la requête d'origine dans la mémoire, est probablement inacceptable, mais la troisième, de la mise en œuvre de la logique comme une question directe à la base de données, restent à explorer.
Merci à tous pour les précieux commentaires.
return MyMappedProp1 && MyMappedProp2
il y a un espoir (pas dans la façon dont vous le faire maintenant, mais dans un autre "à SEC" de façon sans doute). Si vous ouvrez un fichier sur le disque en "faire des trucs" et lire une valeur en dehors de ça, il n'y a probablement pas d'espoir. Tous les général solutions va vous forcer à la requête avec LINQ to Objects, c'est à dire de la charge tout en mémoire avant de filtrer.non, je ne vais pas faire quelque chose mais les requêtes de base de données dans les "trucs"... cependant, voir ma récente mise à jour de cet affichage
Votre exception dans la "mise à jour": avez-vous ce également lorsque vous ne l'utilisez
IEnumerable<Product> xp = db.Quizes.ToList();
? Je crois que ce problème n'a rien à voir avec votre IsShipped
de la propriété. Quelque chose d'autre qui est mauvais dans le modèle.il a à voir avec Darin l'idée de chercher tout d'abord. J'ai utilisé un
IEnumerable
dans les tests, mais ce que je voulais, c'était une liste, donc considérer que List<Product> p1 = db.Quizes.Select(x => x.Component.Product).ToList();
fonctionne très bien mais List<Product> p1 = db.Quizes.ToList().Select(x => x.Component.Product).ToList();
produit d'exception. J'ai besoin de la finale .ToList()
depuis que je suis de l'attribution d'une liste...OriginalL'auteur ekkis | 2011-10-11
Vous devez vous connecter pour publier un commentaire.
La seule façon de faire de cette "SEC" (éviter de répéter la logique à l'intérieur de
IsShipped
dans leWhere
clause de nouveau) et d'éviter le chargement de toutes les données en mémoire avant d'appliquer le filtre est d'extraire le contenu deIsShipped
dans une expression. Vous pouvez ensuite utiliser cette expression comme paramètre àWhere
et dansIsShipped
. Exemple:L', vous pouvez effectuer la requête comme ceci:
Ici, vous devriez avoir qu'un seul lieu de mettre de la logique dans (
IsShippedExpression
) et ensuite l'utiliser pour les requêtes de base de données et dans votreIsShipped
bien ainsi.Puis-je faire? Dans la plupart des cas, probablement pas, parce que la compilation de l'expression est lente. À moins que la logique est très complexe, probablement un sujet à changement et je suis dans une situation où le rendement de l'aide
IsShipped
n'a pas d'importance, je voudrais répéter la logique. Il est toujours possible d'extraire souvent les filtres utilisés dans une méthode d'extension:Et ensuite l'utiliser de cette façon:
Vous disposez de deux places bien que le maintien de la logique: la
IsShipped
de la propriété et de l'extension de la méthode, mais vous pouvez le réutiliser.la logique n'est pas très complexe, mais il nécessite l'instanciation d'une nouvelle copie de l'EF conteneur (pour les recherches) et une boucle, et je ne pouvais pas comprendre comment l'intégrer dans mon top de la requête, c'est pourquoi je l'ai sorti dans une propriété de la classe
en référence à mon dernier commentaire, j'aime votre approche de la requête en extension, cependant, je suis dans la même situation où je ne sais pas comment intégrer une boucle dans une expression... par exemple, si un produit a un certain nombre de composants et j'ai besoin d'itérer à travers eux à la recherche pour les propriétés spécifiques... comment pourrais-je le faire? (Je suis en train d'expérimenter pour voir si je peux le comprendre)
Peut-être mieux ouvrir une autre question. Il semble que vous devez expliquer plus en détail ce que "Faire des trucs" et ce
Component
est vraiment. "...À la recherche pour les propriétés spécifiques..." (à l'exécution) me fait penser qu'il y aura un peu de réflexion impliqués, mais pour moi, votre question n'est pas tangible assez pour donner une réponse. Apparemment, mon exemple de modèle ci-dessus est trop simple pour ce que vous êtes vraiment essayer de faire.oui, vous avez raison. voici la nouvelle question: stackoverflow.com/questions/7787625/...
OriginalL'auteur Slauma
Je devine
IsShipped
est pas associé à un champ dans la base de données? Qui pourrait expliquer pourquoi Linq to entities se plaint - il ne peut pas construire une instruction sql basé sur cette propriété.Est votre
/* do stuff */
à l'intérieur de la propriété basée sur les champs qui sont dans la base de données? Si oui, vous pouvez utiliser cette logique dans votre.Where()
.OriginalL'auteur Jeff Ogata
Vous pouvez consommer le résultat en appelant
.ToList()
et ensuite effectuer le filtre sur le côté client:De sûr, vous devriez être conscient qu'en faisant cela, vous êtes probablement ralentir les performances de votre application vers le bas que les bases de données sont en train de faire cela au mieux.
Je vois votre point de vue. EF ne pouvez pas comprendre comment écrire du SQL pour quoi que ce soit .IsShipped. donc, en substance, j'ai récupérer tout ce qui va être cher; toutes les autres pensées?
oui cela pourrait être cher. Comme je l'ai dit dans ma réponse, la meilleure solution serait d'effectuer l'interrogation à l'intérieur de la base de données (c'est à dire de mettre en œuvre cette logique qu'une requête) ou au moins une partie de celui-ci, afin de réduire le montant de l'ensemble de résultats renvoyés avant d'appliquer une deuxième filtre sur le client.
vous n'êtes pas trompés. En train de faire .ToList() sur un tableau est généralement une mauvaise idée.
OriginalL'auteur Darin Dimitrov
Je suppose que vous voulez dire que vous souhaitez exécuter des requêtes qui n'ont rien à voir avec la bd. Mais ton code ne correspond pas à votre intention. Regardez cette ligne:
La partie qui dit
db.Products
signifie que vous souhaitez interroger la DB.Pour résoudre ce problème, obtenir une entité définie dans la mémoire de la première. Ensuite, vous pouvez utiliser Linq to Objects sur place:
La
.ToList()
finitions de vos initiales DB requête, et vous donne une représentation en mémoire de travailler avec et de le modifier à votre convenance. Après ce point, vous pouvez travailler avec des non-DB propriétés.Attention que si vous faites plus de DB opérations après
ToList
(telles que la modification des propriétés d'une base sur les entités, l'interrogation off propriétés de navigation, etc), alors vous serez de retour dans Linq to entities terre et de ne plus pouvoir le faire Linq to Objects opérations. Vous ne pouvez pas mélanger les deux.Et notez que si
public bool IsShipped()
lit ou écrit DB propriétés ou propriétés de navigation, vous pourriez vous retrouver dans Linq to entities nouveau, si vous ne faites pas attention.Ensuite, la mise en œuvre de
IsShipped
devient important. Si c'est "une série de requêtes de base de données", comment définissez-vous? Sous les couvertures cela devrait être une sorte d'union prolongée, éventuellement à l'aide de sous-requêtes/tables temporaires. Vous pourriez avoir à nous donner votreIsShipped
la mise en œuvre et éventuellement un peu de votre base de données de schéma pour nous d'être en mesure d'aider les autres.Aussi, je l'ai remarqué lors de l'examen de la question: "il y a une fonctionnalité que je ne veux pas construire dans la requête LINQ lui-même". Vous pourriez étudier des solutions qui ont permis à la clause de continuer à faire partie de la requête Linq, mais est définie ailleurs, comme faire un
WhereIsShipped
méthode d'extension pourIQueryable<Product>
. J'ai pris cette approche pour l'encapsulation de la pagination de la logique avant, qui est juste un autre type de critères.Je suis de la poursuite de votre suggestion (et @Slauma) d'une méthode d'extension. J'ai posté un lien dans mon échange avec Slauma à une nouvelle question, qui contient la logique. merci pour votre aide.
OriginalL'auteur Merlyn Morgan-Graham