I have a Comment table which has a CommentID and a ParentCommentID. I am trying to get a list of all children of the Comment. This is what I have so far, I haven’t tested it yet.
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:
- Is there any obvious way to improve this? (Besides maybe creating a view in sql with a CTE.)
- How come I can’t yield a
IEnumerable <Comment>to an IEnumerable<Comment>, onlyCommentitself? - Is there anyway to use SelectMany in this situation?
I’d probably use either a UDF/CTE, or (for very deep structures) a stored procedure that does the same manually.
Note that if you can change the schema, you can pre-index such recursive structures into an indexed/ranged tree that lets you do a single BETWEEN query – but the maintenance of the tree is expensive (i.e. query becomes cheap, but insert/update/delete become expensive, or you need a delayed scheduled task).
Re 2 – you can only
yieldthe type specified in the enumeration (theTinIEnumerable<T>/IEnumerator<T>).You could
yieldanIEnumerable<Comment>if the method returnedIEnumerable<IEnumerable<Comment>>– does that make sense?Improvements:
using, sinceDataContextisIDisposable…so: