지난 포스팅에서는 Entity Framework의 1:N 관계 매핑과 제품(Product)과 카테고리(ProductCategory) 간의 관계 설정 방법을 살펴보았습니다.
이번 글에서는 N:N 관계 매핑을 학습하며, 학생(Student)과 강의(Course) 간의 관계를 예제로 구현하겠습니다.
1. N:N 관계란?

1:N 관계와 달리 N:N 관계는 여러 엔티티가 다른 여러 엔티티와 연결될 수 있는 관계를 의미합니다.
예를 들어, 한 명의 학생(Student)은 여러 강의(Course)에 등록할 수 있고 한 강의는 여러 학생에게 제공되는 경우를 볼 수 있겠죠.
이러한 관계를 구현하기 위해 데이터베이스에서는 중간 테이블(Join Table)을 사용합니다.
1.1 중간테이블(Join Table)
N:N 관계를 구현하려면 중간 테이블이 필요합니다. 중간 테이블은 두 테이블의 관계를 연결하는 역할을 합니다.
이 테이블은 두 엔티티의 외래 키(Foreign Key)를 포함합니다.
중간 테이블은 기본적으로 두 외래 키만 포함합니다.
예를 들어 Student와 Course 간의 중간 테이블은 아래와 같은 구조를 가집니다.
StudentCourses
-------------------
StudentId (FK)
CourseId (FK)
2. N:N 관계 매핑
출처 입력
2.1 시나리오 설명
학생(Student)
- 학생은 여러 강의에 등록할 수 있습니다.
- 등록하지 않은 학생도 있을 수 있으므로 Courses 속성은 nullable로 설정합니다.
강의(Course)
- 강의는 여러 학생이 등록할 수 있습니다.
- 등록된 학생이 없으면 의미가 없으므로 Students 속성은 nullable하지 않고 기본값으로 초기화합니다.
2.2 모델 작성
Student 엔티 생성
namespace EFCoreDemo.Model;
public class Student
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public List<Course>? Courses { get; set; } // 학생은 수업을 듣지 않을 수도 있음
}
Course 엔티티
namespace EFCoreDemo.Model;
public class Course
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public List<Student> Students { get; set; } = default!; // 강의는 반드시 학생과 연결
}
2.3 관계 매핑 코드
OnModelCreating 메서드에 N:N 관계 매핑을 추가합니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
(...)
modelBuilder.Entity<Student>()
.HasMany(s => s.Courses) // 학생은 여러 수업을 들을 수 있음
.WithMany(c => c.Students) // 수업도 여러 학생을 가질 수 있음
.UsingEntity(j => j.ToTable("StudentCourses")); // 중간 테이블 이름을 StudentCourses로 설정
}
3. 관계 매핑 적용 후 마이그레이션
3.1 DbContext 업데이트
DbSet을 추가하여 Student와 Course를 관리합니다.
public DbSet<Student> Students { get; set; } = default!;
public DbSet<Course> Courses { get; set; } = default!;
3.2 마이그레이션 생성 및 적용
변경 사항을 반영하기 위해 아래 명령어를 실행합니다.
dotnet ef migrations add AddStudentCourseRelation
dotnet ef database update
4. 데이터 추가 및 확인
4.1 데이터 추가
SeedDatabase_2 메서드를 생성하여 학생과 강의를 추가하고 관계를 설정합니다.
static void SeedDatabase_2()
{
using var context = new EFCoreDemoDbContext();
// 기존 데이터 삭제
if (context.Students.Any())
{
context.Students.RemoveRange(context.Students);
context.Courses.RemoveRange(context.Courses);
context.SaveChanges();
Console.WriteLine("기존 학생 및 강의 데이터가 삭제되었습니다.");
}
// 새로운 강의 추가
var korean = new Course { Title = "Korean" };
var math = new Course { Title = "Mathematics" };
var science = new Course { Title = "Science" };
var history = new Course { Title = "History" };
// 새로운 학생 추가
var student1 = new Student
{
Name = "Kim",
Courses = [korean, math]
};
var student2 = new Student
{
Name = "Lee",
Courses = [korean, science, history]
};
var student3 = new Student
{
Name = "Park",
Courses = [math]
};
var student4 = new Student
{
Name = "Choi"
};
context.Students.AddRange(student1, student2, student3, student4);
context.SaveChanges();
Console.WriteLine("새로운 학생 및 강의 데이터가 성공적으로 추가되었습니다.");
}
4.2 데이터 확인
모든 학생들과 신청한 과목을 출력하는 메서드를 추가합니다.
static void ReadAllStudents()
{
using var context = new EFCoreDemoDbContext();
var students = context.Students
.Include(s => s.Courses)
.ToList();
Console.WriteLine("학생 목록 및 수업 정보");
foreach (var student in students)
{
Console.WriteLine($"Student: {student.Name}");
if (student.Courses is null || student.Courses.Count == 0)
{
Console.WriteLine(" 신청 과목 없음");
continue;
}
foreach (var course in student.Courses ?? [])
{
Console.WriteLine($" Course: {course.Title}");
}
}
}
4.3 결과
기존 학생 및 강의 데이터가 삭제되었습니다.
새로운 학생 및 강의 데이터가 성공적으로 추가되었습니다.
학생 목록 및 수업 정보
Student: Kim
Course: Korean
Course: Mathematics
Student: Lee
Course: Korean
Course: Science
Course: History
Student: Park
Course: Mathematics
Student: Choi
신청 과목 없음
5. 마치며
이번 글에서는 N:N 관계 매핑의 개념과 구현 방법을 예제를 통해 살펴보았습니다.
이를 통해 여러 엔티티 간의 다대다(N:N) 관계를 효율적으로 처리하고,
중간 테이블을 활용해 관계를 관리하는 방법을 이해할 수 있었습니다.
이로써 기본적인 관계 매핑에 대한 내용은 마무리되었습니다.
이제 다음 포스팅부터는 보다 복잡한 관계 매핑과 성능 최적화를 위한 쿼리 작성법에 대해 알아보며,
실무에서 효율적인 데이터베이스 설계를 지원하는 방법들을 심화 학습해보겠습니다.
'Entity Framework' 카테고리의 다른 글
C# 닷넷 엔티티 프레임워크(Entity Framework) 복잡한 관계 매핑과 쿼리 최적화 (0) | 2025.01.28 |
---|---|
엔티티 프레임워크(Entity Framework) 1:N 관계 매핑 (0) | 2025.01.22 |
EF 1:1 관계 매핑 이해하기 (0) | 2025.01.20 |
EF 데이터베이스 구조 변경 및 마이그레이션 심화 (0) | 2025.01.18 |
Entity Framework를 활용한 CRUD 작업 (0) | 2025.01.15 |