ความสัมพันธ์: หนึ่งต่อหลายและหลายต่อหลาย
จำลองและสืบค้นความสัมพันธ์แบบหนึ่งต่อหลายและหลายต่อหลายด้วยคุณสมบัติการนำทางและ Fluent API
ความสัมพันธ์: หนึ่งต่อหลายและหลายต่อหลาย เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
ความสัมพันธ์ใน EF Core
EF Core จำลองความสัมพันธ์ระหว่างเอนทิตีไว้สามประเภท ได้แก่ หนึ่งต่อหนึ่ง หนึ่งต่อหลาย และ หลายต่อหลาย แต่ละประเภทแสดงด้วยพร็อพเพอร์ตีการนำทาง และสามารถกำหนดค่าเพิ่มเติมด้วย Fluent API ได้
หนึ่งต่อหลาย: การตั้งค่าเอนทิตี
Blog หนึ่งรายการมี Post ได้หลายรายการ เอนทิตีรอง (Post) จะเก็บคีย์นอกไว้ พร็อพเพอร์ตีการนำทางของทั้งสองฝั่งช่วยให้เดินทางไปตามความสัมพันธ์ได้ทั้งสองทิศทาง
public class Blog
{
public int Id { get; set; }
public string Name { get; set; } = "";
public ICollection<Post> Posts { get; set; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; } = "";
public int BlogId { get; set; } // FK
public Blog Blog { get; set; } = null!; // nav property
}Fluent API: หนึ่งต่อหลาย
EF Core อนุมานความสัมพันธ์ตามแบบแผนได้ แต่คุณสามารถกำหนดอย่างชัดเจนด้วย Fluent API เพื่อให้เข้าใจได้ง่ายขึ้นและกำหนดลักษณะการลบแบบส่งต่อ
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Blog>()
.HasMany(b => b.Posts)
.WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);
}การสอบถามด้วย Include (การโหลดล่วงหน้า)
ใช้ Include เพื่อโหลดข้อมูลที่เกี่ยวข้องในการสอบถามเดียวกัน ใช้ ThenInclude เพื่อเจาะลึกลงไปในกราฟการนำทาง
// Load blog with all its posts
var blog = await _db.Blogs
.Include(b => b.Posts)
.FirstOrDefaultAsync(b => b.Id == 1);
// Load posts with their comments too
var blogs = await _db.Blogs
.Include(b => b.Posts)
.ThenInclude(p => p.Comments)
.ToListAsync();หลายต่อหลายโดยไม่มีเอนทิตีเชื่อม
EF Core 5+ รองรับความสัมพันธ์แบบหลายต่อหลายโดยไม่ต้องมีเอนทิตีเชื่อมที่กำหนดเอง โดยจะสร้างตารางเชื่อมโดยอัตโนมัติจากชื่อประเภทเอนทิตี
public class Student
{
public int Id { get; set; }
public string Name { get; set; } = "";
public ICollection<Course> Courses { get; set; } = new List<Course>();
}
public class Course
{
public int Id { get; set; }
public string Title { get; set; } = "";
public ICollection<Student> Students { get; set; } = new List<Student>();
}
// EF creates StudentCourse join table automaticallyหลายต่อหลายที่มีเอนทิตีเชื่อม
เมื่อ ตารางเชื่อมต้องมีคอลัมน์เพิ่มเติม เช่น วันที่ลงทะเบียนหรือเกรด ให้สร้างเอนทิตีเชื่อมโดยเฉพาะพร้อมคีย์หลักแบบผสม
public class Enrollment
{
public int StudentId { get; set; }
public Student Student { get; set; } = null!;
public int CourseId { get; set; }
public Course Course { get; set; } = null!;
public DateTime EnrolledAt { get; set; }
public decimal? Grade { get; set; }
}
// Fluent API config:
mb.Entity<Enrollment>().HasKey(e => new { e.StudentId, e.CourseId });
mb.Entity<Enrollment>().HasOne(e => e.Student).WithMany(s => s.Enrollments);
mb.Entity<Enrollment>().HasOne(e => e.Course).WithMany(c => c.Enrollments);การแทรกข้อมูลที่เกี่ยวข้อง
เพิ่มเอนทิตีที่เกี่ยวข้องลงในคอลเลกชันของเอนทิตีแม่ก่อนเรียกใช้ SaveChangesAsync EF Core จะจัดการค่าของ FK โดยอัตโนมัติ
var blog = new Blog { Name = "Dev Notes" };
blog.Posts.Add(new Post { Title = "Hello EF Core" });
blog.Posts.Add(new Post { Title = "Migrations Deep Dive" });
_db.Blogs.Add(blog);
await _db.SaveChangesAsync();
// Inserts Blog + 2 Posts with correct BlogId FKการกรองข้อมูลที่เกี่ยวข้อง
คุณสามารถกรองด้วยพร็อพเพอร์ตีการนำทางใน LINQ ได้ EF Core จะแปลงการกรองเหล่านี้เป็นคำสั่ง SQL JOIN โดยอัตโนมัติ
// Blogs that have at least one published post
var popularBlogs = await _db.Blogs
.Where(b => b.Posts.Any(p => p.IsPublished))
.Select(b => new { b.Name, PostCount = b.Posts.Count(p => p.IsPublished) })
.OrderByDescending(b => b.PostCount)
.ToListAsync();การลบแบบส่งต่อ
เมื่อใช้ DeleteBehavior.Cascade การลบเอนทิตีหลัก (Blog) จะลบเอนทิตีรองทั้งหมด (Posts) โดยอัตโนมัติ ตัวเลือกอื่น ได้แก่ SetNull, Restrict, NoAction
// Delete a blog and all its posts
var blog = await _db.Blogs.FindAsync(1);
_db.Blogs.Remove(blog!);
await _db.SaveChangesAsync();
// Cascade: all Posts with BlogId=1 are also deletedเอนทิตีที่เป็นเจ้าของสำหรับออบเจ็กต์ค่า
ประเภทเอนทิตีที่เป็นเจ้าของเหมาะอย่างยิ่งสำหรับออบเจ็กต์ค่า เช่น Address โดยจะจัดเก็บไว้ในตารางเดียวกับเอนทิตีเจ้าของ และไม่มีข้อมูลระบุตัวตนแยกเป็นของตนเอง
public class Customer
{
public int Id { get; set; }
public string Name { get; set; } = "";
public Address ShippingAddress { get; set; } = new();
}
public class Address
{
public string Street { get; set; } = "";
public string City { get; set; } = "";
public string Country { get; set; } = "";
}
// Fluent API:
mb.Entity<Customer>().OwnsOne(c => c.ShippingAddress);กรณีใช้งานจริง: คำสั่งซื้อพร้อมรายการสินค้า
รูปแบบอีคอมเมิร์ซที่สมบูรณ์: คำสั่งซื้อ (เอนทิตีหลัก) ที่มี OrderLines หลายรายการ (เอนทิตีรอง) โดยแต่ละรายการอ้างอิงถึง Product
var order = await _db.Orders
.Include(o => o.Lines)
.ThenInclude(l => l.Product)
.FirstOrDefaultAsync(o => o.Id == orderId);
if (order is null) return Results.NotFound();
var summary = new
{
OrderId = order.Id,
Total = order.Lines.Sum(l => l.Quantity * l.Product.Price),
Items = order.Lines.Select(l => new
{
l.Product.Name,
l.Quantity,
LineTotal = l.Quantity * l.Product.Price
})
};
return Results.Ok(summary);ตรวจสอบความเข้าใจ
EF Core จะสร้างตารางเชื่อมโดยอัตโนมัติโดยไม่ต้องมีเอนทิตีเชื่อมที่กำหนดเองเมื่อใด
ทบทวน: ความสัมพันธ์ใน EF Core
ประเด็นสำคัญ:
- หนึ่งต่อหลาย: FK อยู่ที่เอนทิตีรอง มีการนำทางทั้งสองฝั่ง และใช้ Include เพื่อโหลดข้อมูล
- หลายต่อหลาย (แบบง่าย): มีการนำทาง ICollection สองรายการ — EF Core จะสร้างตารางเชื่อมโดยอัตโนมัติ
- หลายต่อหลาย (มีข้อมูลเพิ่มเติม): ใช้เอนทิตีเชื่อมโดยเฉพาะพร้อม PK แบบผสม
- การลบแบบส่งต่อจะควบคุมว่าจะเกิดอะไรขึ้นกับเอนทิตีรองเมื่อเอนทิตีหลักถูกลบ
- เอนทิตีที่เป็นเจ้าของใช้จำลองออบเจ็กต์ค่าในตารางเดียวกับเอนทิตีเจ้าของ
คำถามที่พบบ่อย
บทเรียน “ความสัมพันธ์: หนึ่งต่อหลายและหลายต่อหลาย” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ความสัมพันธ์: หนึ่งต่อหลายและหลายต่อหลาย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ความสัมพันธ์: หนึ่งต่อหลายและหลายต่อหลาย”
จำลองและสืบค้นความสัมพันธ์แบบหนึ่งต่อหลายและหลายต่อหลายด้วยคุณสมบัติการนำทางและ Fluent API คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ความสัมพันธ์: หนึ่งต่อหลายและหลายต่อหลาย” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- พื้นฐาน DbContext และ DbSet
- การย้ายข้อมูลและการจัดการสคีมา
- การดำเนินการ CRUD ด้วย EF Core
- ความสัมพันธ์: หนึ่งต่อหลายและหลายต่อหลาย