2009-02-11 4 views
5

У меня есть таблица комментариев, которая имеет идентификатор CommentID и ParentCommentID. Я пытаюсь получить список всех детей комментария. Это то, что я до сих пор, я еще не тестировал.Linq-to-Sql: рекурсивно получить детей

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 вопроса:

  1. есть ли очевидный способ улучшить это? (Кроме того, возможно создание представления в sql с CTE.)
  2. Почему я не могу дать IEnumerable <Comment> IEnumerable <Comment>, только Comment?
  3. Можно ли использовать SelectMany в этой ситуации?
+0

Является ли это Linq для SQL или Linq для объектов? – bendewey

ответ

4

Я бы использовал либо UDF/CTE, либо (для очень глубоких структур) хранимую процедуру, которая делает то же самое вручную.

Обратите внимание, что если вы можете изменить схему, вы можете предварительно проиндексировать такие рекурсивные структуры в индексированное/ранжированное дерево, которое позволяет выполнить один запрос BETWEEN, но обслуживание дерева дорого (т.е. запрос становится дешевым, но вставка/обновление/удаление становятся дорогостоящими, или вам требуется запланированная задача с задержкой).


Re 2 - вы можете только yield тип, указанный в перечислении (T в IEnumerable<T>/IEnumerator<T>).

yield Вы можете IEnumerable<Comment>если метод возвращал IEnumerable<IEnumerable<Comment>> - это делает смысл?

Улучшения:

  • возможно UDF (держать компонуемости, а не хранимой процедуры), которая использует рекурсию подход CTE
  • использование using, поскольку DataContext является IDisposable ...

так:

using(var db = new MyDataContext()) { /* existing code */ } 
  • LoadWith стоит попробовать, но я не уверен, что я бы надеяться ...
  • список искомых идентификаторов рискованно как поле - я думаю, что ты в порядке, пока вы не «Я называю это дважды ... лично, я бы использовал аргумент для частного метода поддержки ... (т. е. передавать список между рекурсивными вызовами, но не публичным API)
+0

Да, это идеальный смысл, я не уверен, почему они не позволят вам возвращать ienumerable типа или типа tiself – Shawn

+1

Вы можете ** вернуть ** IEnumerable типа. Вы можете ** вернуть доход ** a T. –

+0

право я полностью понял, но я думаю, что вы должны быть в состоянии делать либо – Shawn

Смежные вопросы