2009-02-11 4 views
5

J'ai une table Comment qui a un CommentID et un ParentCommentID. J'essaie d'obtenir une liste de tous les enfants du Commentaire. C'est ce que j'ai jusqu'ici, je ne l'ai pas encore testé.Linq-to-Sql: obtenir récursivement des enfants

private List<int> searchedCommentIDs = new List<int>(); 
// searchedCommentIDs is a list of already yielded comments stored 
// so that malformed data does not result in an infinite loop. 
public IEnumerable<Comment> GetReplies(int commentID) { 
    var db = new DataClassesDataContext(); 
    var replies = db.Comments 
     .Where(c => c.ParentCommentID == commentID 
      && !searchedCommentIDs.Contains(commentID)); 
    foreach (Comment reply in replies) { 
     searchedCommentIDs.Add(CommentID); 
     yield return reply; 
     // yield return GetReplies(reply.CommentID)); // type mis-match. 
     foreach (Comment replyReply in GetReplies(reply.CommentID)) { 
      yield return replyReply; 
     } 
    } 
} 

2 questions:

  1. Y at-il moyen évident d'améliorer cela? (En plus de créer peut-être une vue en sql avec un CTE.)
  2. Comment se fait-il que je ne puisse pas donner un IEnumerable <Comment> à un IEnumerable <Comment>, seulement Comment lui-même?
  3. Est-il possible d'utiliser SelectMany dans ce cas?
+0

Est-ce Linq to SQL ou Linq to Entities? – bendewey

Répondre

4

J'utiliserais probablement soit un UDF/CTE, soit (pour des structures très profondes) une procédure stockée qui fait la même chose manuellement. Notez que si vous pouvez modifier le schéma, vous pouvez pré-indexer ces structures récursives dans une arborescence indexée/à distance qui vous permet de faire une seule requête BETWEEN - mais la maintenance de l'arborescence est coûteuse (c.-à-d. mais insérer/mettre à jour/supprimer devient cher, ou vous avez besoin d'une tâche programmée retardée).


Re 2 - vous ne pouvez yield le type spécifié dans l'énumération (le T dans IEnumerable<T>/IEnumerator<T>).

Vous pouvez yield un IEnumerable<Comment>si renvoyée par la méthode IEnumerable<IEnumerable<Comment>> - Est-ce que ce sens?

Améliorations:

  • peut-être un udf (pour garder composabilité, plutôt qu'une procédure stockée) qui utilise l'approche récursion CTE
  • utilisation using, depuis DataContext est IDisposable ...

ainsi:

using(var db = new MyDataContext()) { /* existing code */ } 
  • LoadWith est la peine d'essayer, mais je ne suis pas sûr que je serais plein d'espoir ...
  • la liste des ids recherchés est risqué comme un champ - Je suppose que vous êtes OK tant que vous n ne l'appelle pas deux fois ... Personnellement, j'utiliserais un argument sur une méthode de support privé ... (ie passer la liste entre les appels récursifs, mais pas sur l'API publique)
+0

Oui, il est tout à fait logique im juste ne sais pas pourquoi ils ne vous laisserait pas non plus retourner un nombre d'un type ou le type tiself – Shawn

+1

Vous pouvez ** renvoyer ** un IEnumerable du type. Vous pouvez ** rapporter ** un T. –

+0

juste comprendre complètement mais je pense que vous devriez être en mesure de faire soit – Shawn

Questions connexes