nunespascal が言ったことを拡張するには:
2 つの別個のテーブルを介して 2 つの別個のエンティティとしてデータを引き戻す場合でも、同じテーブルから多態的にデータを引き戻す場合でも、問題はデータの要求方法にあるようです。
C# 風の EF 擬似コードで次の 2 つのアプローチを検討してください。
アプローチ 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 ステートメントは 2 つだけで、どちらも最初に実行されます。
実際に 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);
}
}