EF를 사용하면서 오래되었지만 여전히 궁굼한점은 코드로 작성된 모델이 어떤형태로 데이터베이스에 매핑이 될 것인가 입니다. 저는 이런 여러가지 의문들을 다양한 테스트를 통해 그 답을 찾아 가고 있습니다. 이번에는 모델이 계층적 구조(상속)로 되어 있을때 데이터베이스에 어떻게 매핑되는지 여러가지 테스트를 해 보았습니다. 테스트를 위한 예로 iCal기반 Calendar의 Event와 Task를 모델로 결정하고 새로운 EF를 사용할 Web API 프로젝트를 생성했습니다. 관련 Package들을 일일이 설치하기 불편하여 프로젝트 생성시 Reference로 MVC와 Web API를 모두 선택하여 템플릿 프로젝트를 만들어 보겠습니다.

일단 Code First의 방법으로 마이그레이션 하기 위한 모델 클래스를 생성해 보겠습니다. 샘플이될 iCal Calendar의 데이터 스키마는 아래와 같습니다.

Models폴더에 아래 세개의 모델 클래스를 생성했습니다.

 public class EventBase
 {
     public int Id { get; set; }
 
     public string Classification { get; set; }
 
     public DateTime StartDate { get; set; }
     public string ExceptionDate { get; set; }
     public DateTime OriginalDate { get; set; }
 
     public int Priority { get; set; }
     public string Status { get; set; }
     public string Description { get; set; }
     public string Summary { get; set; }
     public string Url { get; set; }
 }
 
 public class Event: EventBase
 {
     public bool AllDay { get; set; }
 
     public DateTime FloatingGMTDate { get; set; }
     public int FloatingOffset { get; set; }
     public string Location { get; set; }
 }
 
 public class Task: EventBase
 {
     public DateTime ComplationDate { get; set; }
     public DateTime DueDate { get; set; }
     public bool DueDateIsDateOnly { get; set; }
 }

이런 형태로 모델을 정의 하고 Migration을 위해서 DbContext에 DbSet속성으로 추가했습니다.

public DbSet<EventBase> EventBase { get; set; }
public DbSet<Event> Event { get; set; }
public DbSet<Task> Task { get; set; }

Package Management Console에서 Add-Migration명령을 실행했습니다.

PM> Add-Migration ChangeModels
 Cannot determine a valid start-up project. Using project 'HierarchicalModelTest' instead. Your configuration file and working directory may not be set as expected. Use the -StartUpProjectName parameter to set one explicitly. Use the -Verbose switch for more information.
 Scaffolding migration 'ChangeModels'.
 The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration ChangeModels' again.

Migration으로 자동 생성된 코드는 아래와 같습니다.

 public partial class ChangeModels : DbMigration
 {
     public override void Up()
     {
         CreateTable(
             "dbo.EventBases",
             c => new
                 {
                     Id = c.Int(nullable: false, identity: true),
                     Classification = c.String(),
                     StartDate = c.DateTime(nullable: false),
                     ExceptionDate = c.String(),
                     OriginalDate = c.DateTime(nullable: false),
                     Priority = c.Int(nullable: false),
                     Status = c.String(),
                     Description = c.String(),
                     Summary = c.String(),
                     Url = c.String(),
                     AllDay = c.Boolean(),
                     FloatingGMTDate = c.DateTime(),
                     FloatingOffset = c.Int(),
                     Location = c.String(),
                     ComplationDate = c.DateTime(),
                     DueDate = c.DateTime(),
                     DueDateIsDateOnly = c.Boolean(),
                     Discriminator = c.String(nullable: false, maxLength: 128),
                 })
             .PrimaryKey(t => t.Id);
         
     }
     
     public override void Down()
     {
         DropTable("dbo.EventBases");
     }
 }

생성된 코드를 보면 두 Model Class의 속성들이 모두 합쳐진 형태로 만들어진 것을 확인 할 수 있습니다. 데이터베이스 모델링 차원에서 이렇게 구성하는 것이 맞다 틀리다를 판단하기는 어렵지만, 이 정도의 단순한 계층 구조 모델은 하나의 Entity로 합쳐서 관리하는 것이 효과적이라고 볼수도 있습니다.(애매한 말로 얼버무리는 듯한 느낌이네요.) 어찌되었건, 생성된 테이블에서 Discriminator라는 필드는 EF에 의해 자동 생성되는 필드로서 Event와 Task를 구분하기 위한 식별자를 저장하는 용도로 사용됩니다. 실제 Data row가 추가 되면 생성 모델의 클래스 명이 Discriminator필드에 저장됩니다. 이 테스트에서 Event가 추가되면 “Event”, Task가 추가되면 “Task”라는 문자값이 필드에 저장되게 됩니다.

상속 하위 클래스를 참조하면 참조한 클래스 마다 ForiegnKey가 생성됩니다. 좀더 상세한 설명은 나중에 하기로 하겠습니다.