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个问题:
- 有没有明显的方法来改善这个? (除了可以在带有CTE的sql中创建视图。)
- 为什么我不能将
IEnumerable
到IEnumerable,只有
Comment
本身? - 无论如何在这种情况下使用SelectMany?
我可能使用UDF / CTE,或(对于非常深的结构)手动执行相同操作的存储过程。
请注意,如果您可以更改架构,则可以将此类递归结构预先索引到索引/范围树中,该树允许您执行单个BETWEEN查询 – 但树的维护很昂贵(即查询变得便宜,但插入/更新/ delete变得昂贵,或者您需要延迟的计划任务)。
Re 2 – 您只能生成枚举中指定的类型( IEnumerable
/ IEnumerator
)。
如果方法返回IEnumerable
你可以yield
一个IEnumerable
– 这有意义吗?
改进:
- 也许是使用CTE递归方法的udf (保持可组合性,而不是存储过程)
- 使用,因为
DataContext
是IDisposable
…
所以:
using(var db = new MyDataContext() ) { /* existing code */ }
- LoadWith值得一试,但我不确定我会有希望……
- 搜索的id列表作为一个字段是有风险的 – 我猜你只要你不调用它两次就行了……就个人而言,我会在私人支持方法上使用一个论点…(即通过递归调用之间的列表,但不是公共API之间的列表)