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

时间:2009-02-11 04:27:42

标签: c# sql linq linq-to-sql common-table-expression

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

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. 有没有明显的方法来改善这个? (除了可以在带有CTE的sql中创建视图。)
  2. 为什么我不能将IEnumerable <Comment>提供给IEnumerable <Comment>,只能Comment本身?
  3. 在这种情况下是否仍然使用SelectMany?

1 个答案:

答案 0 :(得分:4)

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

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


Re 2 - 您只能yield枚举中指定的类型(T / IEnumerable<T>中的IEnumerator<T>)。

你可以yield IEnumerable<Comment> ,如果方法返回IEnumerable<IEnumerable<Comment>> - 这有意义吗?

改进:

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

这样:

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