5

我有一个 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 吗?
4

1 回答 1

4

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

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


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

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

改进:

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

所以:

using(var db = new MyDataContext() ) { /* existing code */ }
  • LoadWith值得一试,但我不确定我是否有希望......
  • 搜索到的 id 列表作为一个字段是有风险的 - 我想你没问题,只要你不调用它两次......就个人而言,我会在私有支持方法上使用一个参数......(即通过递归调用之间的列表,但不在公共 API 上)
于 2009-02-11T04:41:30.013 回答