모델 만들기 및 구성

냐옹·2024년 4월 9일
0

.NET

목록 보기
14/31

모델 만들기 및 구성

EF core는 메타데이터 모델을 사용하여 어플리케이션의 엔티티 형식이 기본 데이터 베이스에 매핑되는 방법을 설명한다. 이 모델은 일반적인 패턴을 찾는 [추론]이라는 규칙 집합을 사용하여 빌드되고
그 다음에
OnModelCreating에서 Data annotaion ( 매핑특성 ) 또는 FluentApi (modelbuilder) 를 사용하여 모델을 사용자 지정할 수 있고, 둘다 규칙에 의해 수행되는 구성을 재정의한다.

DbContext 클래스는 EF core에서 모델과 작업하는 주된 수단이다. 이 클래스를 통해서 데이터베이스와의 모든 상호작용을 관리한다. DbContext 내에서 모델을 구성하고, DBset 프로퍼티를 통해서 엔티티에 접근할 수 있다.

Fluent api를 사용하여 모델을 구성하는 방법
파생된 컨텍스트에서 OnModelCreating 메서드를 재정의하고 Fluent api를 사용하여 모델을 구성할 수 있다. 가장 강력한 구성방법으로서 엔티티 클래스를 수정하지 않고도 구성을 지정할 수 있다.
Fluent api 구성은 우선 순위가 가장 높고, 규칙과 DataAnnotation을 재정의한다. 구성은 메서드가 호출되는 순서대로 적용되고 충돌이 있을 경우에 최신 호출이 이전에 지정한 구성을 재정의한다.

 만약에 Fluent api와 Data annotation의 설정이 서로 다르다면?
 Flent api의 설정이 우선한다. ( 이 경우에 data annotation의 설정이 무시된다 )

Fluent api 주요 구성방법

Fluent API와 DataAnnotation 중에서 Fluent API의 사용을 더 권장한다. 그리고 우선 순위 또한 DataAnnotation이 더 높다. 사유는 다음과 같다.

  • 복잡한 모델 구성에 더 유리하고, 데이터 어노테이션으로는 표현할 수 없는 세부적인 설정이 가능하다.
  • 더 명확하다. 데이터 어노테이션 같은 경우는 모델 여러군데에서 따로따로 설정해야하지만, Fluent API는 모델 구성을 OnModelCreating 메서드에 집중시켜서 모델의 구조와 관계를 더 명확하게 파악하기 용이하다.
  • 데이터베이스 스키마를 더 세밀하게 제어할 수 있어서, 복잡한 데이터베이스 스키마를 구성하기에 더 유리하다.
  1. 엔티티와 테이블 매핑
    modelBuilder.Entity ().ToTable(.Blogs’);
    Blog엔티티와 테이블 Blogs 매핑

  2. 기본키 설정
    modelBuilder.Entity().HasKey( b=> b.BlogId )

  3. 관계 정의 ( 일대일, 일대다, 다대다 )
    modelBuilder.Entity()
    .HasOne( p => p.Blog)
    .WithMany( b => b.Posts )
    .HasForeignKey( p=> p.BlogId )

  4. 속성 구성
    modelBuilder.Entity()
    .Property(b => b.url)
    .IsRequired()
    .HasMaxLength(500);

  5. 인덱스 생성
    modelBuilder.Entity()
    .HasIndex( b=> b.url )
    .IsUnique();

다 쉬운 편이지만, 관계 성립이 좀 어렵다. 그래서 더 살펴보겠다.
1. 일대다 관계이다. (블로그의 모델, 관계를 설정하는 것이라고 보자). 하나의 블로그는 여러개의 포스트를 가진다.
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
// Fluent API
modelBuilder.Entity()
.HasMany(b => b.Posts)
.WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId);

  1. 일대일 관계이다. 각 사용자는 한개의 프로필만을 가질 수 있다.
    public class User
    {
    public int UserId { get; set; }
    public string Username { get; set; }
    public UserProfile Profile { get; set; }
    }

public class UserProfile
{
public int UserProfileId { get; set; }
public string Bio { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}

// Fluent API
modelBuilder.Entity()
.HasOne(u => u.Profile)
.WithOne(p => p.User)
.HasForeignKey(p => p.UserId);

  1. 다대다 관계이다. 두 엔티티 유형의 인스턴스가 서로를 여러개 가질 수 있는 관계이다. EF core 5.0부터는 연결 엔티티 없이도 다대다 관계를 직접 정의할 수 있다. 예시로 여기서는 여러 학생이 여러 코스에 등록할 수 있다.
    (연결 엔티티를 사용하는 방법 )
    public class Student
    {
    public int StudentId { get; set; }
    public string Name { get; set; }
    public List Courses { get; set; } = new List();
    }

public class Course
{
public int CourseId { get; set; }
public string Title { get; set; }
public List Students { get; set; } = new List();
}

// Fluent API
modelBuilder.Entity()
.HasMany(s => s.Courses)
.WithMany(c => c.Students)
.UsingEntity(j => j.ToTable("StudentCourses"));
근데 이건 좀 특이한게 엔티티 테이블을 하나 만든다.
StudentCourses 라는 테이블을 하나 만드는데 그 안에는 CoursesId와 PersonsId가 들어가 있다. 왜 이렇게 할까?
없이 해도 된다. 그냥 서로 리스트 포함해서 하면 EF core가 내부적으로 연결 테이블을 처리해준다. 그러나 이런 연결 엔티티가 필요한 경우가 있다.
연결 엔티티를 명시적으로 정의하고 싶거나, 연결 테이블에 추가적인 컬럼 ( 관계 생성날짜, 메모 등 ) 을 포함시켜야 할 경우, 연결 엔티티를 사용할 수 있다.

  1. 복합 키를 사용한 관계정의.. 어떤 경우에는 키가 하나가 아니라 여러개가 섞인, 복합 키를 기반으로 한 관계를 정의해야할 수도 있다. Fluent API를 사용하여 복합키를 구성할 수 있다.
    public class OrderDetail
    {
    public int OrderId { get; set; }
    public int ProductId { get; set; }
    public Order Order { get; set; }
    public Product Product { get; set; }
    }

// Fluent API
modelBuilder.Entity()
.HasKey(od => new { od.OrderId, od.ProductId });

modelBuilder.Entity()
.HasOne(od => od.Order)
.WithMany(o => o.OrderDetails)
.HasForeignKey(od => od.OrderId);

modelBuilder.Entity()
.HasOne(od => od.Product)
.WithMany(p => p.OrderDetails)
.HasForeignKey(od => od.ProductId);

이제 이걸 가지고 백엔드 API를 만들려면..!
DTO data transfer object를 사용한다. dto는 클라이언트가 요청을 보낼 때 필요한 데이터만 포함하여 엔티티의 복잡성을 클라이언트로부터 숨기고, 데이터 전송과정을 최적화 한다.

  1. 시퀀스 생성
    시퀀스는 데이터베이스에서 일련의 숫자를 생성하는데 사용되는 개체이다. 시퀀스는 테이블에 독립적으로 존재하며, 주로 기본키 값을 생성하는데 사용된다. 예를 들어서 테이블에 새로운 행을 추가할 때마다 고유한 숫자를 자동으로 생성하고 싶을 때 시퀀스를 활용할 수 있습니다.
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    // 시퀀스 생성
    modelBuilder.HasSequence("MySequence")
    .StartsAt(1) // 시작 값
    .IncrementsBy(1); // 증가량

    // 엔티티 속성에 시퀀스 사용
    modelBuilder.Entity<MyEntity>()
        .Property(o => o.MyProperty)
        .HasDefaultValueSql("NEXT VALUE FOR MySequence");

    }

public class MyEntity
{
public int Id { get; set; }
public int MyProperty { get; set; } // 시퀀스 값을 받는 속성
}

  1. 상속
    Table-Per-Hierarchy 모델 ( 가장 많이 사용되는 상속 전략 )
    상속을 사용하면 데이터 모델을 더 명확하고 관리하기 쉽게 만들 수 있다.
  • 단계별로
     1. 기본 클래스 정의 모든 상속된 엔티티가 공유할 속성을 포함하는 기본 클래스를 정의한다.
     2. 파생 클래스 정의
    기본 클래스에서 상속받아 특정 엔티티에 특화된 속성을 추가하는 하나 이상의 파생 클래스를 정의한다.
     3. DbContext에 클래스 등록 _ EF core가 모델을 인식하도록 DbContext에 엔티티 클래스를 추가한다.
     4. 마이그레이션 생성 및 데이터베이스 업데이트 : 모델 변경 사항을 데이터베이스에 적용하기 위한 마이그레이션을 생성하고 실행한다.
     음 별로 쓸일 없을 것 같은데
     조회성능에는 좋지만 테이블이 커지고 NULL이 많아진다는데, 나는 NULL 있는거 자체가 사실 별로 싫다. 런타임 에러는 무서워
  1. 지원필드

0개의 댓글