0Pricing
C# Academy · บทเรียน

การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง

ควบคุมเวลาที่ข้อมูลที่เกี่ยวข้องถูกโหลดด้วย Include, ThenInclude, พร็อกซีสำหรับการโหลดแบบขี้เกียจ และการเรียก Load อย่างชัดแจ้ง

การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

กลยุทธ์การโหลดสามแบบ

EF Core มีกลยุทธ์สามแบบสำหรับโหลดข้อมูลที่เกี่ยวข้อง ได้แก่ การโหลดล่วงหน้า (โหลดพร้อมกับการสอบถาม) การโหลดเมื่อเรียกใช้ (โหลดเมื่อมีการเข้าถึง) และ การโหลดอย่างชัดแจ้ง (โหลดเมื่อต้องการ) การเลือกวิธีที่เหมาะสมช่วยหลีกเลี่ยงปัญหา N+1 และการส่งคำขอไปกลับฐานข้อมูลที่ไม่จำเป็น

การโหลดล่วงหน้าด้วย Include

การโหลดล่วงหน้าใช้ Include() เพื่อ JOIN ข้อมูลที่เกี่ยวข้องในคำสั่งสอบถาม SQL เดียวกัน วิธีนี้คาดการณ์ผลลัพธ์ได้ง่ายที่สุดและช่วยหลีกเลี่ยงปัญหา N+1

// Single query with JOIN
var blogs = await _db.Blogs
    .Include(b => b.Posts)
    .Where(b => b.IsActive)
    .ToListAsync();

// SQL: SELECT * FROM Blogs LEFT JOIN Posts ON ...

ThenInclude สำหรับความสัมพันธ์แบบซ้อนกัน

ThenInclude จะเชื่อมต่อการโหลดให้ลึกลงไปในกราฟการนำทาง คุณสามารถโหลดข้อมูลหลายระดับได้ในการสอบถามเดียว

var orders = await _db.Orders
    .Include(o => o.Customer)
    .Include(o => o.Lines)
        .ThenInclude(l => l.Product)
            .ThenInclude(p => p.Category)
    .Where(o => o.Status == OrderStatus.Pending)
    .ToListAsync();

Include แบบกรองข้อมูล

EF Core 5+ รองรับการกรองข้อมูลที่เกี่ยวข้องภายใน Include ทำให้คุณโหลดเอนทิตีลูกเพียงบางส่วนได้โดยไม่ต้องใช้การสอบถามแยกต่างหาก

// Load only published posts for each blog
var blogs = await _db.Blogs
    .Include(b => b.Posts.Where(p => p.IsPublished)
                         .OrderByDescending(p => p.PublishedAt)
                         .Take(5))
    .ToListAsync();

การตั้งค่าการโหลดเมื่อเรียกใช้

การโหลดเมื่อเรียกใช้จะโหลดพร็อพเพอร์ตีการนำทางโดยอัตโนมัติในครั้งแรกที่มีการเข้าถึง เปิดใช้โดยติดตั้งแพ็กเกจ Microsoft.EntityFrameworkCore.Proxies และเรียกใช้ UseLazyLoadingProxies()

// 1. Install package: dotnet add package Microsoft.EntityFrameworkCore.Proxies
// 2. Enable in DbContext setup:
builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlite(connStr)
       .UseLazyLoadingProxies());

// 3. Mark navigation properties as virtual:
public class Blog
{
    public int Id { get; set; }
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
}

การโหลดเมื่อเรียกใช้จริง (และกับดัก N+1)

การโหลดเมื่อเรียกใช้สะดวก แต่เป็นอันตรายเมื่อใช้ในลูป เพราะการเข้าถึงแต่ละครั้งจะส่งคำสั่งสอบถาม SQL ใหม่ ทำให้เกิดปัญหา N+1 ในกรณีที่แสดงรายการ ควรเลือกใช้การโหลดล่วงหน้าเสมอ

var blogs = await _db.Blogs.ToListAsync(); // 1 query

foreach (var blog in blogs)
{
    // BAD: each access fires a new query!
    var count = blog.Posts.Count; // N queries
    Console.WriteLine(count);
}

// FIX: Use eager loading
var blogs2 = await _db.Blogs.Include(b => b.Posts).ToListAsync();

การโหลดอย่างชัดแจ้ง

การโหลดอย่างชัดแจ้งช่วยให้คุณโหลดพร็อพเพอร์ตีการนำทางเมื่อต้องการ โดยใช้ Entry().Collection().LoadAsync() หรือ Entry().Reference().LoadAsync() เหมาะสำหรับกรณีที่คุณต้องการข้อมูลที่เกี่ยวข้องเป็นบางเงื่อนไข

var blog = await _db.Blogs.FindAsync(1); // no posts loaded

// Load posts only when needed
if (needsPosts)
{
    await _db.Entry(blog!)
             .Collection(b => b.Posts)
             .LoadAsync();
}

// Load single reference
var post = await _db.Posts.FindAsync(99);
await _db.Entry(post!)
         .Reference(p => p.Blog)
         .LoadAsync();

การโหลดอย่างชัดแจ้งพร้อมตัวกรองการสอบถาม

คุณสามารถกรองการโหลดอย่างชัดแจ้งได้โดยใช้ .Query() ก่อนเรียกใช้ LoadAsync() เพื่อลดปริมาณข้อมูลที่ส่งกลับ

var blog = await _db.Blogs.FindAsync(1);

// Only load posts published this year
await _db.Entry(blog!)
         .Collection(b => b.Posts)
         .Query()
         .Where(p => p.PublishedAt.Year == DateTime.UtcNow.Year)
         .LoadAsync();

Console.WriteLine(blog!.Posts.Count);

การสอบถามแบบแบ่งส่วนสำหรับ Include จำนวนมาก

การโหลดคอลเลกชันหลายรายการในคิวรีเดียวทำให้เกิดการเพิ่มจำนวนแบบคาร์ทีเซียน (แถวจะถูกคูณเพิ่มขึ้น) ใช้ AsSplitQuery() เพื่อส่งคิวรีแยกกันสำหรับแต่ละคอลเลกชัน แล้วนำมารวมกันในหน่วยความจำ

var orders = await _db.Orders
    .Include(o => o.Lines)
    .Include(o => o.Shipments)
    .AsSplitQuery()  // 3 separate SELECTs instead of one giant JOIN
    .ToListAsync();

// Or configure globally:
opt.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);

การเลือกเฉพาะข้อมูลเพื่อหลีกเลี่ยงการดึงข้อมูลเกินจำเป็น

แทนที่จะโหลดเอนทิตีทั้งหมดพร้อมความสัมพันธ์ทั้งหมด ให้เลือกเฉพาะข้อมูลที่ต้องการไปยังออบเจ็กต์ถ่ายโอนข้อมูลด้วย Select วิธีนี้จะได้ข้อมูลตรงตามที่ต้องการในคิวรีเดียวที่ปรับให้เหมาะสมแล้ว

var summaries = await _db.Blogs
    .Select(b => new BlogSummaryDto
    {
        Name      = b.Name,
        PostCount = b.Posts.Count(p => p.IsPublished),
        LatestPost = b.Posts
            .Where(p => p.IsPublished)
            .OrderByDescending(p => p.PublishedAt)
            .Select(p => p.Title)
            .FirstOrDefault()
    })
    .ToListAsync();
// No Include needed - translated to subqueries

ในสถานการณ์จริง: การเลือกกลยุทธ์ที่เหมาะสม

นำแนวทางตัดสินใจนี้ไปใช้ได้จริง:

  • การโหลดล่วงหน้า + Include: ต้องใช้ข้อมูลที่เกี่ยวข้องเสมอ เช่น หน้ารายการ
  • การเลือกเฉพาะข้อมูล: มุมมองแบบอ่านอย่างเดียวและการตอบกลับ API — มีประสิทธิภาพสูงสุด
  • การโหลดแบบระบุชัด: โหลดตามเงื่อนไขที่กำหนดโดยตรรกะของแอป
  • การโหลดแบบเลื่อนเวลา: ควรหลีกเลี่ยงในแอปเว็บ ใช้เฉพาะกับเดสก์ท็อปหรือสคริปต์ที่มีชุดข้อมูลขนาดเล็ก

ตรวจสอบความเข้าใจ

ปัญหา N+1 ในบริบทของการโหลดแบบเลื่อนเวลาคืออะไร

สรุป: กลยุทธ์การโหลด

ประเด็นสำคัญ:

  • การโหลดล่วงหน้า (Include): โหลดข้อมูลในคิวรีเดียว เหมาะที่สุดสำหรับรูปแบบการเข้าถึงที่คาดการณ์ได้
  • Include แบบกรองข้อมูล: โหลดเฉพาะข้อมูลลูกค้าบางส่วน — รองรับตั้งแต่ EF Core 5+
  • การโหลดแบบเลื่อนเวลา: สะดวกแต่มีความเสี่ยง — หลีกเลี่ยงการใช้ในลูป (ปัญหา N+1)
  • การโหลดแบบระบุชัด: โหลดเมื่อจำเป็นและควบคุมได้ละเอียด
  • การเลือกเฉพาะข้อมูลด้วย Select: มีประสิทธิภาพสูงสุดสำหรับกรณีอ่านอย่างเดียว
  • คิวรีแบบแยกส่วน: หลีกเลี่ยงการเพิ่มจำนวนแบบคาร์ทีเซียนเมื่อใช้ Include กับคอลเลกชันหลายรายการ

คำถามที่พบบ่อย

บทเรียน “การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง”

ควบคุมเวลาที่ข้อมูลที่เกี่ยวข้องถูกโหลดด้วย Include, ThenInclude, พร็อกซีสำหรับการโหลดแบบขี้เกียจ และการเรียก Load อย่างชัดแจ้ง คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การโหลดแบบทันที แบบขี้เกียจ และแบบชัดแจ้ง
  2. SQL ดิบ โพรซีเยอร์ที่จัดเก็บ และการแทรกค่า
  3. คำสั่งสืบค้นที่คอมไพล์แล้วและประสิทธิภาพ
  4. ตัวกรองคำสั่งสืบค้นส่วนกลางและเอนทิตีที่เป็นเจ้าของ
← กลับไปที่ C# Academy