動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
C#

パターン1: 罠 (Include 忘れ + foreach 内 navigation)

出典: EF6 + LINQ で N+1 問題を踏まない3つの書き方3パターンのコード比較 (動作確認つき) / パターン1: 罠 (Include 忘れ + foreach 内 navigation)

パターン1: 罠 (Include 忘れ + foreach 内 navigation) (csharp)#19cd61cdd189
class Customer { public int Id; public string Name = ""; }
class Order { public int Id; public int CustomerId; public int Amount; }
 
var customers = new List<Customer> {
    new() { Id = 1, Name = "A社" },
    new() { Id = 2, Name = "B社" },
    new() { Id = 3, Name = "C社" },
};
var orders = new List<Order> {
    new() { Id = 1, CustomerId = 1, Amount = 1000 },
    new() { Id = 2, CustomerId = 1, Amount = 2000 },
    new() { Id = 3, CustomerId = 2, Amount = 3000 },
};
 
int sqlCount = 0;
List<Order> GetOrdersByCustomer(int cid) {
    sqlCount++;
    Console.WriteLine($"[SQL #{sqlCount}] SELECT * FROM Orders WHERE CustomerId = {cid}");
    return orders.Where(o => o.CustomerId == cid).ToList();
}
 
Console.WriteLine("[SQL #0] SELECT * FROM Customers");
foreach (var c in customers) {
    var cOrders = GetOrdersByCustomer(c.Id);
    Console.WriteLine($"  {c.Name}: 注文 {cOrders.Count} 件");
}
Console.WriteLine($"発行 SQL 合計: {sqlCount + 1} 本 (顧客 {customers.Count} 件 + 1)");
▸ 実行ボタンで結果を表示
  • id: #19cd61cdd189
  • lines: 27
  • extracted: 2026-06-10
  • captured: 2026-06-10

Source収録記事

この snippet は記事の「3パターンのコード比較 (動作確認つき) / パターン1: 罠 (Include 忘れ + foreach 内 navigation)」セクションに登場する。コードの前後の文脈・ハマりどころの解説は記事本文で。

同じ記事から

7
C#
// 開発時はこれで動いた
var customers = db.Customers.ToList();
foreach (var c in customers) {
    // 顧客ごとに c.Orders を見る ← ここで1ループに1 SQL 飛ぶ
▶ 実行可

なぜ「LINQ 書いたら SQL が爆発する」のか

#044de404ad21
C#
// EF6 (.NET Fx 4.7.2)・これが本番で爆発するやつ
using var db = new MyDbContext();
var customers = db.Customers.ToList();   // SQL #1: SELECT * FROM Customers
foreach (var c in customers) {
▶ 実行可

パターン1: 罠 (Include 忘れ + foreach 内 navigation)

#0cd0b26748ea
C#
// EF6 (.NET Fx 4.7.2)・Include で関連を1クエリにまとめる
using var db = new MyDbContext();
var customers = db.Customers
    .Include(c => c.Orders)             // JOIN Orders を含める
▶ 実行可

パターン2: Include で eager loading (1クエリで関連ごと取得)

#8a5aff026173
C#
Console.WriteLine("[SQL #1] SELECT c.*, o.* FROM Customers c LEFT JOIN Orders o ON c.Id = o.CustomerId");
var customersWithOrders = customers
    .GroupJoin(orders,
        c => c.Id,
▶ 実行可

パターン2: Include で eager loading (1クエリで関連ごと取得)

#a218fe1f714f
C#
// EF6 (.NET Fx 4.7.2)・Select で必要な列だけ射影
using var db = new MyDbContext();
var summary = db.Customers
    .Select(c => new {
▶ 実行可

パターン3: Select 射影で1クエリ集計 (画面に出す列だけ)

#ea190218fcb0
C#
Console.WriteLine("[SQL #1] SELECT c.Name, (SELECT COUNT(*) FROM Orders o WHERE o.CustomerId = c.Id) AS OrderCount, (SELECT ISNULL(SUM(o.Amount),0) FROM Orders o WHERE o.CustomerId = c.Id) AS TotalAmount FROM Customers c");
var summary = customers
    .Select(c => new {
        c.Name,
▶ 実行可

パターン3: Select 射影で1クエリ集計 (画面に出す列だけ)

#9ac91d59371f
図鑑トップ