ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • EF Core - Code First
    .NET/Database 2025. 1. 11. 18:58

    Code First란 ?

    데이터베이스 스키마를 코드에서 정의하고, 이를 기반으로 데이터베이스를 생성하거나 유지보수하는 방식입니다.

     

    생산성을 향상하는 부분에서 Code First 방식이 필요한 이유

    개발을 하다보면 종종 SQL작업과 코드를 번갈아가면서 작업해야하는 경우가 종종 발생합니다. 하지만 여러 언어를 전환하면서 작업하는 것은 상당히 피로한 일 입니다. SQL 역시 마찬가지 입니다. 백엔드 개발자라면 SQL에 대해서 어느정도 이상 사용할 수 있는 것이 너무나도 당연하지만 전환작업에서의 피로감은 피할 수 없습니다. 

     

    이런 부분에서 코드 퍼스트 방식을 사용하게 되면, 데이터베이스 스키마 정의와 성능상에서 지장이 없는 부분에 쿼리에 대해서 기존 개발언어만 사용해서 개발 할 수 있습니다. C#의 EF Core는 dotnet cli를 통해 굉장히 편하게 사용할 수 있도록 제공해주고 있습니다. 이번 포스트를 통해서 어떻게 C# EF Core로 코드퍼스트 방식으로 Database를 관리하는지 소개합니다.

     

    이번 포스트는 JetBrains Rider를 사용하여 작성하도록 하겠습니다.

    JetBrains Rider도 Visual Studio 처럼 커뮤니티 버전은 이제 무료로 사용 할 수 있으니 설치만 하고 따라하시면 됩니다. 

    예제는 eShop을 시뮬레이션 해보겠습니다.

     

    준비 사항

    데이터베이스 생성 

    로컬 docker에 위와 같이 postgresql 도커를 생성하고 실행하였습니다. 

    docker run --name postgres-container -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=dldpvmzhdj12!@ -e POSTGRES_DB=shop -p 5432:5432 -v postgres_data:/var/lib/postgresql/data -d postgres

     

    프로젝트 생성

    새 솔루션 > 클래스 라이브러리 

    타깃 프레임워크  > net9.0

    솔루션 이름은 자유롭게 적어주시고, 프로젝트 이름은 Database라고 작성했습니다.

     

    패키지 설치

     

     

    왼쪽 탐색기에서 Database 프로젝트를 우클릭 후 Nuget 패키지 관리를 선택합니다.

    이후 하단 패키지 관리자에서 그림에 나온 세가지 패키지를 Database 프로젝트에 추가합니다.

    혹은 database.csproj 파일이 있는 위치에서 

    dotnet add package Microsoft.EntityFrameworkCore --version 9.0.0
    dotnet add package Microsoft.EntityFrameworkCore.Design --version 9.0.0
    dotnet add package Microsoft.EntityFrameworkCore.Tools --version 9.0.0
    dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 9.0.0

    터미널로 위의 커맨드을 입력하시면 패키지가 설치됩니다. 

     

    각각의 패키지가 어떤 역할을 하는지는 이전 포스트에서 다룬바 있습니다.

    여기서 간단하게 Todo List를 기록하는 데이터베이스를 만들어 보도록 하겠습니다.

     

    디렉토리 구조 작업

    그 전에 DB엔터티와 연결을 담당하는 객체인 DbContext를 넣어둘 디렉토리를 생성하여 구조를 잡습니다.

     

    Entity 폴더에는 각 데이터베이스 테이블 스키마가 들어갈 예정이고, 

    Context에는 Db와 연결하는데 사용하는 DbContext 관련코드가 들어갈 예정입니다.

     

     

     

    Product 스키마 클래스 생성

    public class Product
    {
        [Key]
        public int ProductId { get; set; }
        
        public ProductCategory Category { get; set; }
    
        [Required]
        [MaxLength(255)]
        public string ProductName { get; set; }
    
        [MaxLength(500)]
        public string? Description { get; set; }
    
        [Column(TypeName = "decimal(10,2)")]
        public decimal Price { get; set; }
        
        public DateTimeOffset CreatedAt { get; set; } = DateTime.UtcNow;
    }
    
    public enum ProductCategory
    {
        Electronic,
        Food,
        Clothing
    }

    Entity 폴더에 Production.cs를 작성해줍니다.

     

    ProductionCategory는 EnumType 이지만, 특별한 설정이 없다면 Database에서 int타입으로 인식합니다. EF Core에서 Enum 타입으로 넘겨주게 되면, 사용하는 개발자가 조금 더 편하게 이타입이 어떤 타입인지 인식하기가 편한 장점이 있습니다. 

    String 타입은 code first시에는 반드시 타입 길이를 작성하는게 좋습니다. 작성하지 않을경우 최대길이로 생성됩니다. 

    DbContext 작성

    그리고 Db와 연결되는 DbContext를 작성합니다.

    using Microsoft.EntityFrameworkCore;
    using Database.Entity;
    
    namespace Database.Context;
    
    public partial class ShopDbContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
        
        public ShopDbContext(DbContextOptions<ShopDbContext> options) 
            :base(options)
        {
            
        }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            
        }
    }

    간단하게 이렇게 작성해줍니다. 

     

    dotnet tool ef 설치

    이제 이것을 실제 DataBase에 옮겨야합니다. 그전에 dotnet ef cli가 설치되어 있지 않다면 설치해주세요

    dotnet tool install --global dotnet-ef

     

    마이그레이션 작업은 Database 프로젝트가 아닌 또 다른 프로젝트를 생성하도록 하겠습니다.

    마이그레이션 버전 관리 코드와 스키마와 dbcontext 코드가 섞여있는 것을 원하지 않기 때문입니다. 

    PIS 솔루션 파일을 우클릭 > 추가 > 새 프로젝트

    아까와 마찬가지로 net9 버전의 클래스라이브러리로 Migrator 프로젝트를 생성합니다.

    생성된 Migration 프로젝트를 우클릭 > 추가 > 참조 >Database 체크 > 추가 합니다.

    이렇게 종속 요소 > 프로젝트를 확장해서 보면 방금 만든 Database 프로젝트가 들어가있어야 합니다. 

     

    EF Core는 콘솔, asp.net core와 같은 실행 프로젝트가 아닌 라이브러리 프로젝트에서 코드 작성 타이밍에 DB 마이그레이션을 할수 있도록 DesignTimeFactory를 제공합니다. 

    Migration 프로젝트 패키지 설치 

    dotnet add package Microsoft.EntityFrameworkCore.Design --version 9.0.0
    dotnet add package Microsoft.Extensions.Configuration.Json --version 9.0.0
    dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 9.0.0

    json 값으로 connectionstring을 받기위한 패키지와 sqlite 쿼리 프로바이더 입니다.

    dbms는 실습을 위해 간단한 Sqlite로 진행했습니다.

     

    디자인 타임 팩토리 코드 작성 

    using Database.Context;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Design;
    using Microsoft.Extensions.Configuration;
    
    namespace Migrator;
    
    public class TodoDbContextFactory : IDesignTimeDbContextFactory<TodoDbContext>
    {
        public TodoDbContext CreateDbContext(string[] args)
        {
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile($"appsettings.json")
                .Build();
    
            var builder = new DbContextOptionsBuilder<TodoDbContext>();
            var connectionString = configuration.GetConnectionString("DefaultConnection");
    
            builder.UseSqlite(connectionString
                , b=> b.MigrationsAssembly("Migrator"));
    
            return new TodoDbContext(builder.Options);
        }
    }

    마이그레이션 프로젝트에 위와같이 작성합니다. 

    json에서 커넥션 스트링을 가져오도록 처리하고 싶으므로 appsettings.json도 작성해줍니다. 

    {
      "ConnectionStrings": {
        "DefaultConnection": "Server=localhost;Port=5432;Database=shop;Username=postgres;Password=dldpvmzhdj12!@;"
      }
    }

    이렇게하면 현재위치에 database.db 파일을 생성하고 관리하도록 되어있습니다. 

     

    데이터베이스에 반영하기 

    Migrator.csproj 가 있는 위치에서 아래 터미널을 실행해야합니다.

    dotnet ef migrations add init
    dotnet ef database update

     

    정상적으로 진행되었다면 

     

     

     

    위와 같이 데이터베이스에 정상적으로 Products 테이블이 생성되고, 마이그레이션 정보가 등록된 것을 볼 수 있습니다.

     

    추후에 엔터티가 추가되는 경우에는 다시한번

    dotnet ef Migrations add <마이그레이션명칭>

    dotnet ef database update를 통해서  다시 마이그레이션 해줍니다. 

     

    주의할 점

    코드퍼스트 방식을 사용 할때 주의할 점은 코드퍼스트 이후에 db에서 직접 변경시에는 마이그레이션 내용과 실제 db의 내용에 차이가 발생하게 됩니다.

    이후에는 마이그레이션으로 처리가 안되는 상황이 온다면, 마이그레이션 파일과 테이블을 모두 지우고, 전체 스캐폴드를 받아 초기 마이그레이션으로 진행하거나, 그 상황 시점부터 DB First 방식으로 진행되어야 합니다. 

     

    이 방식에는 팀내에서의 합의가 되어있어야 정상적으로 활용이 가능합니다. 개인적으로 개발할 때에는 DB부분에 대한 관리가 적어지므로써 얻는 장점이 매우 크기 때문에, Code First는 추천합니다.

    하지만 팀내에서 개발하고, 전문적인 DBA 분들과 함께한다면, Code First를 하지 않는게 더 좋을 수 있습니다.

     

    그렇지만 Code First 하지 않더라도 EF Core를 활용해서 얻을 수 있는 장점들은 많이 있습니다.

    다음 포스트에서는 EF Core의 Table Mapping 방식에 대해서 설명하겠습니다.

Designed by Tistory.