2010-01-02 3 views
3

Comment écrire des sous-requêtes comme celles-ci dans EF?Sous-requête Entity Framework

select * from table1 where col1 in (select col1 from table2 where col2 = 'xyz') 

ou

select * from table1 where col1 not in (select col1 from table2 where col2 = 'xyz') 

J'ai essayé quelque chose comme ces

from t1 in table1 
where (from t2 in table2 where col2 = 'xyz' select t2.col1).Contains(t1.col1) 
select t1 

et

from t1 in table1 
where !(from t2 in table2 where col2 = 'xyz' select t2.col1).Contains(t1.col1) 
select t1 

ces requêtes fonctionnent bien LINQPad ou LINQ to sql

+0

Dans le cas où les réponses existantes ne correspondent pas à vos attentes, veuillez publier * ce qui s'est passé * lorsque vous avez essayé d'utiliser les expressions de requête que vous avez publiées. Avez-vous eu une erreur de compilation? Erreur d'exécution? Quelle était l'erreur? Ou n'avez-vous tout simplement pas obtenu les résultats que vous attendiez? – Aaronaught

+0

tout d'abord merci pour la réponse immédiate! c'est ce que je suis en train d'accomplir - select * from table1 où somestringmanipulation (col1) dans (sélectionnez somestringmanipulation (col1) de table2 où 'xyz' col2 =) où Table1 et Table2 n'a pas de relations . Je reçois l'erreur suivante lorsque j'essaie d'utiliser Contient, mais il donne des résultats dans LinqPad LINQ to Entities ne reconnaît pas la méthode 'Boolean Contient [Int32] (System.Linq.IQueryable'1 [System. Int32], Int32) ', et cette méthode ne peut pas être traduite en une expression de magasin. – Gokulnath

+0

Je ne pense pas que je peux accomplir cela sans utiliser IN ou NOT IN, pour le moment j'avais prévu d'utiliser la procédure stockée et plus tard, je vais regarder dans http://stackoverflow.com/questions/374267/contains -workaround-using-linq-to-entities – Gokulnath

Répondre

0

S'il y a une clé étrangère en place, vous devez simplement utiliser les propriétés d'association et de laisser EF traduire dans le bon joint/sous-requêtes, comme:

from t1 in table1 
where t1.Table2.col2 == "xyz" 
select t1 

Pas sûr de votre scénario spécifique, mais une différence clé est que EF par défaut de ne pas faire le chargement paresseux, de sorte que vous pouvez avoir besoin de colonnes Include() (n'aurait pas besoin de cela dans linq-à-sql ou LinqPad qui utilise linq-à-sql) pour les charger, ou alternativement Charger() après.

http://msdn.microsoft.com/en-us/library/bb896249.aspx

Si vous pourriez finir par partager un peu plus concret schéma, nous pourrions dire à coup sûr si c'est ce qui se passe, je l'espère.

+2

Le chargement différé ne devrait pas être un problème ici car il s'agit d'une transformation de requête - il n'évalue jamais réellement 't1.Table2.col2' dans le CLR. S'il y a une différence entre Linq et SQL (que LinqPad utilise), alors je suppose que c'est parce qu'EF ne sait pas comment transformer l'expression comme elle est écrite, mais bien sûr nous devrons savoir ce qui s'est réellement passé quand il a essayé son requêtes afin d'être sûr. – Aaronaught

+0

Aaron a raison: Le chargement paresseux (ou pas) * ne sera pas un facteur ici. –

6

Ce type de sous-requête peut être aplati à une jointure, ce qui est la façon dont je choisirais d'écrire ici:

Version SQL:

SELECT t1.col1, t1.col2, t1.col3, ... 
FROM table1 t1 
INNER JOIN table2 t2 
    ON t1.col1 = t2.col1 
WHERE t2.col2 = 'xyz' 

Linq Version:

var query = 
    from t1 in context.Table1 
    where t1.AssociationToTable2.Col2 == "xyz" 
    select new { t1.Col1, t1.Col2, ... }; 

AssociationToTable2 est la propriété de relation - elle effectue automatiquement la jointure. Ou, si vous ne disposez pas d'une relation:

var query = 
    from t1 in context.Table1 
    join t2 in context.Table2 
     on t1.Col1 equals t2.Col1 
    where t2.Col2 == "xyz" 
    select new { t1.Col1, t1.Col2, ... }; 

Vous pouvez les adapter en conséquence pour NOT IN, bien que je vous recommande de ne jamais utiliser NOT IN si vous pouvez l'éviter - la performance coulera et cela implique presque toujours une erreur dans la conception.

Si vous devez absolument faire le "IN" façon, je suggère de passer en revue les réponses dans this question.