Entity Framework에서 사용되는 다섯 가지 주요 매핑 패턴

첫 번째 매핑

테이블당 계층 구조(TPH: Table-Per-Hierarchy) 상속 매핑

모델 파일:

using System.Data.Entity;

namespace EFMapping
{
    public class CourseContext : DbContext
    {
        public DbSet<LearningCourse> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<LearningCourse>()
                .Map<LearningCourse>(m => m.Requires("Category").HasValue("Basic"))
                .Map<WebCourse>(m => m.Requires("Category").HasValue("Web"));
        }
    }

    public class LearningCourse
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Duration { get; set; }
    }

    public class WebCourse : LearningCourse
    {
        public string Link { get; set; }
    }
}

생성된 데이터베이스 스크립트:

CREATE TABLE [dbo].[Courses] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [Name] NVARCHAR(MAX) NULL,
    [Duration] INT NOT NULL,
    [Link] NVARCHAR(MAX) NULL,
    [Category] NVARCHAR(128) NOT NULL,
    CONSTRAINT [PK_Courses] PRIMARY KEY CLUSTERED ([Id] ASC)
);

기본 전략을 사용한 경우 코드는 다음과 같습니다:

using System.Data.Entity;

namespace EFMapping
{
    public class CourseContext : DbContext
    {
        public DbSet<LearningCourse> Courses { get; set; }
    }

    public class LearningCourse
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Duration { get; set; }
    }

    public class WebCourse : LearningCourse
    {
        public string Link { get; set; }
    }
}

데이터베이스 스크립트:

CREATE TABLE [dbo].[Courses] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [Name] NVARCHAR(MAX) NULL,
    [Duration] INT NOT NULL,
    [Link] NVARCHAR(MAX) NULL,
    [Discriminator] NVARCHAR(128) NOT NULL,
    CONSTRAINT [PK_Courses] PRIMARY KEY CLUSTERED ([Id] ASC)
);

구분자 열은 자동으로 "Discriminator"로 명명되며 클래스 이름을 저장합니다.

두 번째 매핑

테이블당 유형(TPT: Table-Per-Type) 상속 매핑

모델 파일:

using System.Data.Entity;

namespace EFMapping
{
    public class CourseContext : DbContext
    {
        public DbSet<LearningCourse> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<LearningCourse>().ToTable("LearningCourses");
            modelBuilder.Entity<WebCourse>().ToTable("WebCourses");
        }
    }

    public class LearningCourse
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Duration { get; set; }
    }

    public class WebCourse : LearningCourse
    {
        public string Link { get; set; }
    }
}

생성된 데이터베이스 스크립트:

CREATE TABLE [dbo].[LearningCourses] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [Name] NVARCHAR(MAX) NULL,
    [Duration] INT NOT NULL,
    CONSTRAINT [PK_LearningCourses] PRIMARY KEY CLUSTERED ([Id] ASC)
);

CREATE TABLE [dbo].[WebCourses] (
    [Id] INT NOT NULL,
    [Link] NVARCHAR(MAX) NULL,
    CONSTRAINT [PK_WebCourses] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_WebCourses_LearningCourses] FOREIGN KEY ([Id]) REFERENCES [dbo].[LearningCourses]([Id])
);

CREATE NONCLUSTERED INDEX [IX_Id]
ON [dbo].[WebCourses]([Id] ASC);

파생 클래스의 테이블은 기본 클래스와 외래 키를 통해 연결됩니다.

세 번째 매핑

테이블당 콘크리트 클래스(TPC: Table-Per-Concrete Class) 상속 매핑

모델:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;

namespace EFMapping
{
    public class CourseContext : DbContext
    {
        public DbSet<LearningCourse> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<WebCourse>().Map(m =>
            {
                m.MapInheritedProperties();
                m.ToTable("WebCourses");
            });
        }
    }

    public class LearningCourse
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }
        public string Name { get; set; }
        public int Duration { get; set; }
    }

    public class WebCourse : LearningCourse
    {
        public string Link { get; set; }
    }
}

생성된 데이터베이스 스크립트:

CREATE TABLE [dbo].[LearningCourses] (
    [Id] INT NOT NULL,
    [Name] NVARCHAR(MAX) NULL,
    [Duration] INT NOT NULL,
    CONSTRAINT [PK_LearningCourses] PRIMARY KEY CLUSTERED ([Id] ASC)
);

CREATE TABLE [dbo].[WebCourses] (
    [Id] INT NOT NULL,
    [Name] NVARCHAR(MAX) NULL,
    [Duration] INT NOT NULL,
    [Link] NVARCHAR(MAX) NULL,
    CONSTRAINT [PK_WebCourses] PRIMARY KEY CLUSTERED ([Id] ASC)
);

주키는 전체 계층 구조에서 고유해야 합니다.

네 번째 매핑

엔티티 타입의 속성을 데이터베이스의 여러 테이블에 매핑(Entity Splitting)

모델:

using System.Data.Entity;

namespace EFMapping
{
    public class DepartmentContext : DbContext
    {
        public DbSet<Department> Departments { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Department>()
                .Map(m =>
                {
                    m.Properties(t => new { t.Id, t.Name });
                    m.ToTable("Departments");
                })
                .Map(m =>
                {
                    m.Properties(t => new { t.Id, t.FoundedDate });
                    m.ToTable("DepartmentDetails");
                });
        }
    }

    public class Department
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime FoundedDate { get; set; }
    }
}

생성된 데이터베이스 스크립트:

CREATE TABLE [dbo].[Departments] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [Name] NVARCHAR(MAX) NULL,
    CONSTRAINT [PK_Departments] PRIMARY KEY CLUSTERED ([Id] ASC)
);

CREATE TABLE [dbo].[DepartmentDetails] (
    [Id] INT NOT NULL,
    [FoundedDate] DATETIME NOT NULL,
    CONSTRAINT [PK_DepartmentDetails] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_DepartmentDetails_Departments] FOREIGN KEY ([Id]) REFERENCES [dbo].[Departments]([Id])
);

CREATE NONCLUSTERED INDEX [IX_Id]
ON [dbo].[DepartmentDetails]([Id] ASC);

각 테이블에는 주키가 포함됩니다.

다섯 번째 매핑

데이터베이스의 한 테이블에 여러 엔티티 유형 매핑(Table Splitting)

모델 파일:

using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace EFMapping
{
    public class InstructorContext : DbContext
    {
        public DbSet<Teacher> Teachers { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Teacher>()
                .HasRequired(t => t.OfficeDetail)
                .WithRequiredPrincipal(t => t.Teacher);

            modelBuilder.Entity<Teacher>().ToTable("Teachers");
            modelBuilder.Entity<OfficeDetail>().ToTable("Teachers");
        }
    }

    public class Teacher
    {
        public int Id { get; set; }
        public string FullName { get; set; }

        public OfficeDetail OfficeDetail { get; set; }
    }

    public class OfficeDetail
    {
        [Key]
        public int TeacherId { get; set; }
        public string RoomNumber { get; set; }

        public Teacher Teacher { get; set; }
    }
}

생성된 데이터베이스 스크립트:

CREATE TABLE [dbo].[Teachers] (
    [Id] INT IDENTITY (1, 1) NOT NULL,
    [FullName] NVARCHAR(MAX) NULL,
    [RoomNumber] NVARCHAR(MAX) NULL,
    CONSTRAINT [PK_Teachers] PRIMARY KEY CLUSTERED ([Id] ASC)
);

태그: EntityFramework TPH TPT TPC

7월 4일 01:04에 게시됨