扩展 nunespascal 所说的:
无论您是通过两个单独的表将数据作为两个单独的实体拉回,还是从同一个表中以多态方式将其拉回,听起来您遇到的问题是您如何请求数据。
在 C#-ish EF 伪代码中考虑这两种方法:
方法 1:迭代加载子项
var posts = db.Posts;
foreach (Post p in posts) {
Html.Render(p);
var comments = db.Comments.Where(c => c.PostId == p.PostId);
foreach (Comment c in comments) {
Html.Render(c);
}
}
这听起来像是您在当前的中继器迭代中基本上正在做的事情。对于您来到的每个帖子,加载属于它的评论 - 并将它们呈现出来。
这正是您所描述的瓶颈,您正在打开/关闭大量连接并运行大量单独的原子 SQL 语句。如果可以,请避免这种情况。
方法 2:一起加载父母/孩子
var posts = db.Posts.Top(10);
// ^ The .Top(10) limits the result-set to a manageable number of posts (10).
var ids = posts.Select(p => p.PostId);
// ^ This line creates an Enumerable list of the IDs of your loaded posts.
var comments = db.Comments.Where(c => ids.Contains(c.PostId));
// ^ This line loads all the comments which belong to the 10 posts you loaded.
foreach (Post p in posts) {
Html.Render(p);
foreach (Comment c in comments.Where(c => c.PostId == p.PostId)) {
// This loop iterates the comments in the same way the previous example
// showed, with the exception that it iterates *in memory*, rather than
// running additional SQL on each iteration.
Html.Render(c);
}
}
因为您在第二个示例中加载了内存中的所有项目,所以您保存了所有往返行程 - 只创建了 2 个 SQL 语句,这两个语句都在开始时运行。
如果您实际上使用的是 EF4/5(上面的代码基于),您实际上甚至可以执行以下操作:
var posts = db.Posts.Include("Comments");
// ^ This line loads both Posts and Comments in a single SQL statement
foreach (Post p in posts) {
Html.Render(p);
foreach (Comment c in p.Comments) {
// EF5 and other ORMs can create a .Comments property which contains an
// Enumerable list of the comments, already filtered on the FK binding
Html.Render(c);
}
}