2010-03-09 4 views
0

Les gourous LINQ, Je cherche aide pour écrire une requête ...LINQ aide de la requête nécessaire pour Intersection

J'ai une table avec les dossiers de personne, et il a une colonne de ParentID annulable, il est une sorte d'auto -référence, où chaque enregistrement peut avoir un parent.

Je recherche des lignes non traitées dont les lignes parent ont été traitées. Cette SQL fonctionne très bien:

SELECT * 
    FROM Person 
    where IsProcessed = 0 and 
    ParentId in 
    (
    select Id from Person 
    where IsProcessed = 1 
) 

J'ai essayé un certain nombre de requêtes LINQ, mais ils ont échoué. Maintenant, je suis en train:

var qParent = 
       from parent in db.Person 
       where 
       parent.IsProcessed == true 
       select parent.ID; 

    var qChildren = from child in db.Person 
        where 
        child.IsProcessed == false 
        && child.ParentId.HasValue 
        select child.ParentId.Value; 

    var q2 = qChildren.Intersect(qParent); 

Cela donne SQL avec une clause DISTINCT, pour une raison quelconque, et je suis dérouté pourquoi DISTINCT est généré.

Ma question principale est comment écrire LINQ pour l'instruction SQL ci-dessus?

Merci d'avance.

Répondre

3

Intersection est une opération définie - elle est destinée à renvoyer un ensemble d'éléments distincts de l'intersection. Il me semble raisonnable qu'il utiliserait DISTINCT dans le SQL. Par exemple, il peut y avoir plusieurs enfants avec le même parent. Par exemple, Intersect ne doit renvoyer cet ID qu'une seule fois.

Y a-t-il une raison pour laquelle vous ne voulez pas utiliser une jointure ici?

var query = from parent in db.Person 
      where parent.IsProcessed 
      join child in db.Person.Where(child => !child.IsProcessed) 
       on parent.ID equals child.ParentId.Value 
      select child; 
+0

oui, je suis d'accord qu'une jointure est le chemin à parcourir. Je l'ai tourné un peu pour le rendre plus logique à lire: var q = de l'enfant dans db.Person où child.IsProcessed rejoindre des parents dans db.Person sur child.ParentID.value égaux parents!. ID où parent.IsProcessed sélectionnez enfant; merci beaucoup, Jon –

0

La requête peut être traduit littéralement:

var parentIds = db.Person.Where(x => x.IsProcessed) 
         .Select(x => x.Id) 
         .ToList(); 
var result = db.Person.Where(x => !x.IsProcessed && parentIds.Contains(x => x.Id)) 
        .ToList(); 
+0

merci beaucoup Obalix. Votre requête fonctionne aussi, mais peut être moins efficace que la jointure en raison de l'opération parent toList(), ou peut-être pas. J'ai corrigé l'erreur de syntaxe comme étant: parentIds.Contains (x.Id.value) en supprimant la répétition x =>. –

+0

Eh bien, pas beaucoup. La requête parent est exécutée une fois (ne contient que des identifiants) puis elle est placée dans Linq to SQL et devient 'SELECT ... FROM ... WHERE isprocessed = 0 && id dans (1, 2, 3 ...)'. Et cela s'exécute assez rapidement, mais vous utilisez évidemment la solution de jointure. Qui ose conradiquer Jon Skeet? N'oubliez pas d'accepter la réponse avec laquelle vous êtes satisfait. – AxelEckenberger