Linq-to-Sql:递归获取子项

我有一个Comment表,它有一个CommentID和一个ParentCommentID。 我想获得评论中所有孩子的清单。 这是我到目前为止,我还没有测试过。

private List searchedCommentIDs = new List(); // searchedCommentIDs is a list of already yielded comments stored // so that malformed data does not result in an infinite loop. public IEnumerable 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. 有没有明显的方法来改善这个? (除了可以在带有CTE的sql中创建视图。)
  2. 为什么我不能将IEnumerable 到IEnumerable ,只有Comment本身?
  3. 无论如何在这种情况下使用SelectMany?

我可能使用UDF / CTE,或(对于非常深的结构)手动执行相同操作的存储过程。

请注意,如果您可以更改架构,则可以将此类递归结构预先索引到索引/范围树中,该树允许您执行单个BETWEEN查询 – 但树的维护很昂贵(即查询变得便宜,但插入/更新/ delete变得昂贵,或者您需要延迟的计划任务)。


Re 2 – 您只能生成枚举中指定的类型( IEnumerable / IEnumerator )。

如果方法返回IEnumerable>你可以yield一个IEnumerable – 这有意义吗?

改进:

  • 也许是使用CTE递归方法的udf (保持可组合性,而不是存储过程)
  • 使用,因为DataContextIDisposable

所以:

 using(var db = new MyDataContext() ) { /* existing code */ } 
  • LoadWith值得一试,但我不确定我会有希望……
  • 搜索的id列表作为一个字段是有风险的 – 我猜你只要你不调用它两次就行了……就个人而言,我会在私人支持方法上使用一个论点…(即通过递归调用之间的列表,但不是公共API之间的列表)