일대다 관계 설정하기

Casecade Delete를 이해하기에 앞서, Entity를 일대다로 연관관계를 맺는방법을 알아야합니다.

순수하게 Db설계에서는 단순하게 자식테이블의 특정 id가 부모의 외래키가 설정된 케이스입니다.


어노테이션 VS Flent API : 혼합및 양자택일가능합니다.

어노테이션으로 설정Fluent API사용하여 설정
[Table("tokenhistory")]
public class TokenHistory
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int TokenHistoryId { get; set; }
          
    [ForeignKey("UserForeignKey")]
    public User User { get; set; }


}

[Table("user")]
public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    public List<TokenHistory> TokenHistorys { get; set; }
}
public class AccountContent : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<TokenHistory> TokenHistories { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        //관계설정
        modelBuilder.Entity<TokenHistory>()                
            .HasOne(t => t.User)
            .WithMany(b => b.TokenHistorys);
    }
}

일대다 관계형성을 위한 외래키설정은  어노테이션만으로도 할수 있으며, 객 체의 순수성을 보장하기위해 ( 객체에는 객체만 정의)

FluentAPI를 통해 설정도 가능합니다. 각각은 장단점이 있음으로 일괄적인 방식을 위해 어느 한가지 방식을 선택하면 되겠습니다.

특수한 DDL의 경우 어노테이션이 지원하지 않는 케이스도 있기때문에, 마이그레이션을 포함하여 DDL까지 모두 커버하려면 

FluentAPI 를 사용한 일괄적 방법이 권장됩니다.


위 코드를 살펴보면, ORM이  DDL까지 할수 있습니다. DB 초기설정시 중요한 역활을 할수 있지며 마이그레이션에서도 중요한 역활을 부여할수가 있습니다. 

권한및 역활에따라 다음과 같은 용어로 분류가 되며 ORM은 아래 3가지를 OOP방식으로 모두 일괄적인 방법으로 할수있는 장점이 있습니다.

  • DDL(Data Definitison Language)의 테이블 객체의 생성(Create),변경(Alert),삭제(Drop)을 포함하여 Index설정등을 할수 있음
  • DML(Data Manipulation Language) : 스키마객체의 데이터를 Insert/Update/Select등을 할수 있는 명령어(표준화되어있어서 거의 공통)
  • DCL(Data Control Language) : Commit,RollBack,SavePoint등을 할수 있는 명령어(DB종속적인 경우가 많음)

위 장점이 있음에도 불구하고 ORM이 가지는 오해는 , DBA가 가지고 있는 DDL에 관한 권한때문입니다.

ORM은 어플리케이션 코드에 관계맵핑을 명확하게 하는것이 주목적이며, 그로인해 DDL까지 가능한것은 부가적인 기능으로 볼수 있습니다.

운영중 엔티티가 변경되고 어플리케이션도 적절하게 반영되어야하는 마이그레이션 문제는 ORM과 상관없이 엄격하고,디테일한 정책이 적용되어야하는 문제이며

DDL에 관한 기존 정책을 유지하면서 ORM 사용이 가능합니다.


다음은 DDL을 이용하지 않고, ORM을 사용하는 전략입니다.

https://docs.microsoft.com/ko-kr/ef/core/get-started/aspnetcore/existing-db


하위항목 삭제

일대다(부모 vs 자식) 관계에서  부모만 삭제한다고 가정해봅시다. DBMS에서는

다음과 같은전략 3가지중 하나를 선택할수가 있습니다.

  • 자식/종속을 삭제할 수 있습니다.
  • 자식의 외래 키 값을 null로 설정할 수 있습니다.
  • 자식을 변경하지 않고 그대로 유지합니다.

하지만 DBMS마다 위 트리거를 이용하는 방법은 각각 다를것이며, 고아(부로를 잃는)를 방지하기 위한

제약조건을 거는 방법도 각각 다를것입니다.


FluentAPI설정의 OnDelete 설정을 통해, 

public class AccountContent : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<TokenHistory> TokenHistories { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        //관계설정및 삭제전략
        modelBuilder.Entity<TokenHistory>()                
            .HasOne(t => t.User)
            .WithMany(b => b.TokenHistorys)
            .OnDelete(DeleteBehavior.Cascade);

        //인덱스 설정
        modelBuilder.Entity<TokenHistory>()
            .HasIndex(t => new { t.AuthToken })
            .IsUnique(true);
    }  
}
  • ClientSetNull : 메모리 객체에서만 Null이됩니다.
  • Restrict : 그냥 방치합니다. ( 고아가 생김)
  • SetNull : 외래키를 Null로 셋팅하여 참조관계를 끊어주기만 합니다. 이후에 일괄적인 정리가 가능합니다.
  • Cascade : 자식 객체를 모두 제거합니다.


MSDN 공식문서 :https://docs.microsoft.com/ko-kr/ef/core/saving/cascade-delete




  • No labels