C#

EF Core 최신 N 연관관계 매핑

검은고양이개발자 2024. 7. 14. 22:55
반응형

EF Core에서 N(Many-to-Many) 관계 매핑

Entity Framework Core (EF Core)는 객체-관계형 매퍼(ORM)로, 데이터베이스와 객체 지향 프로그래밍을 연결하는 데 도움을 줍니다. EF Core 5.0 이상 버전에서는 Many-to-Many (N) 관계를 보다 간편하게 설정할 수 있습니다. 이 글에서는 최신 EF Core를 사용하여 Many-to-Many 관계를 설정하고, 이를 활용하는 방법을 설명합니다.

 

1. Many-to-Many 관계 개요


Many-to-Many 관계는 두 엔티티가 서로 여러 관계를 가질 수 있는 경우를 의미합니다. 예를 들어, 학생(Student)은 여러 과목(Course)을 수강할 수 있고, 과목도 여러 학생이 수강할 수 있습니다.

 

 

2. 모델 클래스 정의


EF Core 5.0 이상에서는 중간 엔티티를 명시적으로 정의하지 않고도 Many-to-Many 관계를 설정할 수 있습니다. 이를 위해 학생(Student)과 과목(Course) 클래스는 다음과 같이 정의됩니다.

 


public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }
    public ICollection<Course> Courses { get; set; }
}

public class Course
{
    public int CourseId { get; set; }
    public string Title { get; set; }
    public ICollection<Student> Students { get; set; }
}

 

3. DbContext 설정


DbContext에서 OnModelCreating 메서드를 통해 Many-to-Many 관계를 설정합니다.

public class SchoolContext : DbContext
{
    public DbSet<Student> Students { get; set; }
    public DbSet<Course> Courses { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student>()
            .HasMany(s => s.Courses)
            .WithMany(c => c.Students)
            .UsingEntity<Dictionary<string, object>>(
                "StudentCourse",
                j => j.HasOne<Course>().WithMany().HasForeignKey("CourseId"),
                j => j.HasOne<Student>().WithMany().HasForeignKey("StudentId"));
    }
}

 

4. 데이터 추가 및 조회


4-1 데이터 추가

기존의 Course 엔티티가 이미 존재하는 경우, 새로운 Student를 생성하고 기존 Course와 연관시킬 수 있습니다.

using (var context = new SchoolContext())
{
    // 데이터베이스에서 기존 Course를 검색
    var existingCourse = context.Courses.FirstOrDefault(c => c.Title == "Mathematics");

    if (existingCourse != null)
    {
        // 새로운 Student 생성
        var student = new Student { Name = "Jane Doe" };

        // 기존 Course와 연관
        student.Courses = new List<Course> { existingCourse };

        // Student 추가
        context.Students.Add(student);

        // 변경사항 저장
        context.SaveChanges();
    }
}

 

4-2 데이터 조회

학생과 관련된 과목 정보를 함께 조회하려면 Include 메서드를 사용합니다.

using (var context = new SchoolContext())
{
    var students = context.Students
        .Include(s => s.Courses)
        .ToList();

    foreach (var student in students)
    {
        Console.WriteLine($"{student.Name} is enrolled in the following courses:");

        foreach (var course in student.Courses)
        {
            Console.WriteLine(course.Title);
        }
    }
}

 

5. 학생 엔티티 업데이트 (과목 추가 및 수정)


 

과목 추가

if (student != null)
{
    // 새로운 과목 생성
    var newCourse = new Course { Title = "Physics" };

    // 학생의 과목 목록에 추가
    student.Courses.Add(newCourse);

    // 변경사항 저장
    context.SaveChanges();
}

 

과목 수정

if (student != null)
{
    // 학생의 첫 번째 과목을 수정 (예제)
    var course = student.Courses.FirstOrDefault();
    if (course != null)
    {
        course.Title = "Advanced Mathematics";
    }

    // 변경사항 저장
    context.SaveChanges();
}

 

과목 제거

if (student != null)
{
    // 첫 번째 과목을 제거 (예제)
    var courseToRemove = student.Courses.FirstOrDefault();
    if (courseToRemove != null)
    {
        student.Courses.Remove(courseToRemove);
    }

    // 변경사항 저장
    context.SaveChanges();
}

 

6. 예외 처리 및 개선


데이터베이스 작업 중 발생할 수 있는 오류를 처리하기 위해 예외 처리를 추가할 수 있습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;

public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }
    public ICollection<Course> Courses { get; set; }
}

public class Course
{
    public int CourseId { get; set; }
    public string Title { get; set; }
    public ICollection<Student> Students { get; set; }
}

public class SchoolContext : DbContext
{
    public DbSet<Student> Students { get; set; }
    public DbSet<Course> Courses { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student>()
            .HasMany(s => s.Courses)
            .WithMany(c => c.Students)
            .UsingEntity<Dictionary<string, object>>(
                "StudentCourse",
                j => j.HasOne<Course>().WithMany().HasForeignKey("CourseId"),
                j => j.HasOne<Student>().WithMany().HasForeignKey("StudentId"));
    }
}

public class Program
{
    public static void Main()
    {
        using (var context = new SchoolContext())
        {
            try
            {
                // 데이터베이스에서 기존 Course를 검색
                var existingCourse = context.Courses.FirstOrDefault(c => c.Title == "Mathematics");

                if (existingCourse != null)
                {
                    // 새로운 Student 생성
                    var student = new Student { Name = "Jane Doe" };

                    // 기존 Course와 연관
                    student.Courses = new List<Course> { existingCourse };

                    // Student 추가
                    context.Students.Add(student);

                    // 변경사항 저장
                    context.SaveChanges();
                }
                else
                {
                    Console.WriteLine("Course not found.");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }
    }
}

 

반응형