[EF Core] ASP.NET Core & EF Core(Npgsql & PostgreSQL)

참조


목적

  • .NET 6 환경에서 ASP.NET Core 와 EF Core 를 이용하여 PostgreSQL Database 환경에서 ORM 환경 구축 되도록 개발 진행합니다.

개발 환경

  • 개발 환경은 다음과 같습니다.
    • OS : Windows 10
    • .NET Version : .NET 6
    • IDE : Visual Studio 2022
    • Database : PostgreSQL

1. ASP.NET Core 웹앱(MVC) 프로젝트 생성

  • Visual Studio 2022 를 실행하여, ASP.NET Core 웹앱(MVC) 프로젝트를 생성합니다.
  • 프로젝트 이름은 MovieApp 이라고 명명하였습니다.


2. 클래스 라이브러리 생성

  • ASP.NET Core 웹앱(MVC) 프로젝트를 생성 완료 하였다면, 다음으로는 클래스 라이브러리 프로젝트 하나를 새롭게 추가합니다.
  • 새롭게 추가하는 클래스 라이브러리 이름은 MovieApp.Data 로 명명 하였습니다.


3. 프로젝트 구조

  • 프로젝트 구조는 다음과 같습니다.
  • 크게 2개의 프로젝트 구조를 가지고 있습니다.
    • MovieApp(ASP.NET Core 웹앱 프로젝트)
    • MovieApp.Data(클래스 라이브러리)


4. MovieApp 프로젝트 -> 종속성 -> MovieApp.Data 참조 추가

  • 다음으로 웹앱 프로젝트인 MovieApp 프로젝트 종속성에 MovieApp.Data 클래스 라이브러리 참조 되도록 참조 추가 진행합니다.
  • 참조 추가하는 방법은 다음과 같습니다.
    • MovieApp -> 종속성(dependency) -> 프로젝트 참조 추가
    • MoviewApp.Data 체크박스 선택(체크)


5. MovieApp 프로젝트 DB 정보 추가

  • 다음으로 MoviewApp 프로젝트에서 appsettings.json 파일에 접속하고자 하는 Database 정보를 입력합니다.
  • 해당 접속 정보는 Database 종류별로 차이가 있고, 저는 PostgreSQL Database 정보 기준으로 작성 진행합니다.
  • 다음 정보에서 제가 추가한 정보는 ConnectionStrings 정보입니다.
  • ConnectionStrings 정보 안에는 MoviesDb 라고 해서, PostgreSQL 에 접속할 대상 Database 정보를 입력합니다.

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MoviesDb": "Server=localhost;Database=JoBeomHee;Port=5432;User Id=JoBeomHee;Password=1234;"
  }
}

6. Movie Model 추가

  • 다음으로 MovieApp.Data 클래스 라이브러리로 다시 돌아 옵니다.
  • 그리고 Movie.cs 클래스를 추가하여 Movie Model 을 추가합니다.
  • 참고로, Movie 클래스 안에는 Actor 클래스가 있습니다.

Movie.cs

using System.ComponentModel.DataAnnotations;

namespace MovieApp.Data
{
    public class Movie
    {
        public int Id { get; set; } 
        [Required]
        public string Title { get; set; }   
        public int Year { get; set; }   
        public string Summary { get; set; } 
        [MaxLength(3)]
        public List<Actor> Actors { get; set; }
    }

    public class Actor
    {
        public int Id { get; set; }
        [Required]
        public string Fullname { get; set; }
    }
}

7. Npgsql.EntityFrameworkCore.PostgreSQL 패키지 추가

  • 다음으로 MovieApp.Data 클래스 라이브러리에 Npgsql.EntityFrameworkCore.PostgreSQL NuGet Package 를 추가합니다.


8. MovieDataContext.cs 추가

  • 앞서, Npgsql.EntityFrameworkCore.PostgreSQL NuGet Package 를 추가하였습니다.
  • 다음으로 MoviewApp.Data 클래스 라이브러리에 MovieDataContext.cs 클래스를 추가하고 다음과 같이 코드를 작성합니다.

MovieDataContext.cs

using Microsoft.EntityFrameworkCore;

namespace MovieApp.Data
{
    public class MovieDataContext : DbContext
    {
        public MovieDataContext(DbContextOptions<MovieDataContext> options) :
            base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.UseSerialColumns();
        }

        public DbSet<Movie> Movies { get; set; }    
        public DbSet<Actor> Actors { get; set; }
    }
}

9. Migration(마이그레이션)

  • Migration 작업 이란, EF Core에서 Code First C# 모델 클래스로부터 Database 와 Table 을 생성하기 위한 작업입니다.
  • Migration은 초기 DB/Table 생성 뿐만 아니라, 중간에 Table 구조가 변경될 경우 이러한 변화는 DB에 적용하는 작업을 합니다.
  • 앞서 만들었던 Movie, Actor 2개의 Model Migration 작업을 진행해 보도록 하겠습니다.

Microsoft.EntityFrameworkCore.Tools 패키지 추가

  • Migration 작업을 진행하기 위해서는 Microsoft.EntityFrameworkCore.Tools NuGet Package 가 사전에 설치가 되어 있어야 합니다.
  • MovieApp.Data 클래스 라이브러이에 Microsoft.EntityFrameworkCore.Tools NuGet Package 를 설치 합니다.


Migration 시작

  • 앞서, Microsoft.EntityFrameworkCore.Tools NuGet Package 추가를 완료 하였다면 이제 Migration CLI 명령어를 실행하여 Migration 작업을 진행하면 됩니다.
  • 도구 -> NuGet 패키지 관리자 -> 패키지 관리자 콘솔 을 실행합니다.
  • 그리고 아래와 같은 명령어를 실행합니다.

> Add-Migration InitialDatabase
  • 실행 결과, 정상 실행 되면 다음 로그가 기록됩니다.
    Build started...
    Build succeeded.
    Microsoft.EntityFrameworkCore.Infrastructure[10403]
        Entity Framework Core 6.0.3 initialized 'MovieDataContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL:6.0.3+94d0a8eaeb9cf5af6ce55a9e59153c1a1be3244f' with options: None
    To undo this action, use Remove-Migration.

Migrations 폴더 생성 확인

  • 앞서 Add-Migration InitialDatabase 명령어를 통해 Migration 작업을 진행하였습니다.
  • 해당 작업이 성공적으로 끝났다면, MovieApp.Data 클래스 라이브러리 위치에 Migrations 폴더가 생성된 것을 확인할 수 있습니다.


ORM 대상 Database 에 Update

  • 이제 생성된 Migrations 정보를 실제 데이터베이스인 PostgreSQL 에 Update 해서 PostgreSQL Database 에도 정보가 반영 되도록 해야 합니다.
  • 마찬가지로 도구 -> NuGet 패키지 관리자 -> 패키지 관리자 콘솔 을 실행합니다.
  • 그리고 아래와 같은 명령어를 실행합니다.
> Update-Database

  • 실행 결과, 정상 실행 되면 다음 로그가 기록됩니다.
Build started...
Build succeeded.
Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.3 initialized 'MovieDataContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL:6.0.3+94d0a8eaeb9cf5af6ce55a9e59153c1a1be3244f' with options: None
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (64ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT EXISTS (SELECT 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace WHERE c.relname='__EFMigrationsHistory');
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (133ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE "__EFMigrationsHistory" (
          "MigrationId" character varying(150) NOT NULL,
          "ProductVersion" character varying(32) NOT NULL,
          CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
      );

....생략.....

PostgreSQL Database 확인

  • 실제로 PostgreSQL Database 에 Migration 했던 정보들이 제대로 반영 되었는지 확인합니다.
  • 확인 결과 Movie, Actor 2개의 Table 이 정상적으로 생성된 것을 확인할 수 있습니다.


10. 데이터 추가

  • 이제 Migration 까지 모두 완료 하였기 때문에, 실제 ASP.NET Core 웹 프로젝트에서 데이터를 추가해 보도록 하겠습니다.

ViewModels 폴더 생성

  • 데이터를 추가하기에 앞서, 내가 추가한 데이터를 웹 UI 로 보기 위하여 ViewModels 폴더를 생성하고, 해당 경로에 MovieViewModel.cs 클래스를 추가하여 아래와 같은 코드를 추가합니다.
  • MovieApp/ViewModels/MovieViewModel.cs
namespace MovieApp.ViewModels
{
    public class MovieViewModel
    {
        public string Title { get; set; }
        public string Year { get; set; }
        public string Summary { get; set; }
        public string Actors { get; set; }
    }
}

Views/Home/Index.cshtml 수정

  • 이제 다음으로 Views/Home/Index.cshtml 경로에 가서 다음과 같이 코드를 수정합니다.
@model IEnumerable<MovieApp.ViewModels.MovieViewModel>

@{
    ViewData["Title"] = "Movie";
}

@foreach(var movie in Model)
{
    <h1>@movie.Title</h1>
    <p>@movie.Year</p>
    <p class="m-2">@movie.Summary</p>
    <p>@movie.Actors</p>
}

Seed 클래스 생성

  • 다음으로 DataSeeder.cs 클래스를 생성하여 데이터를 추가하는 로직을 작성합니다.
  • DataSeeder.cs
using MovieApp.Data;

namespace MovieApp
{
    public static class DataSeeder
    {
        public static void Seed(this IHost host)
        {
            using var scope = host.Services.CreateScope();
            using var context = scope.ServiceProvider.GetRequiredService<MovieDataContext>();
            context.Database.EnsureCreated();
            AddMovies(context);
        }

        private static void AddMovies(MovieDataContext context)
        {
            var movie = context.Movies.FirstOrDefault();
            if (movie != null) return;

            context.Movies.Add(new Movie
            {
                Title = "The Shawshank Redemption",
                Year = 1994,
                Summary = "Banker Andy Dufresne is arrested for killing his wife and her lover. After a hard adjustment, he tries to improve the conditions of the prison and to give hope to his companions.",
                Actors = new List<Actor>
                {
                    new Actor { Fullname = "Morgan Freeman"},
                    new Actor { Fullname = "Tim Robbins"}
                }
            });

            context.Movies.Add(new Movie
            {
                Title = "The Godfather",
                Year = 1972,
                Summary = "The aging patriarch of a New York mafia dynasty passes the torch of his underground empire to his reluctant son",
                Actors = new List<Actor>
                {
                    new Actor { Fullname = "Marlon Brando" },
                    new Actor { Fullname = "Al Pacino " },
                }
            });

            context.Movies.Add(new Movie
            {
                Title = "The Dark Knight",
                Year = 2008,
                Summary = "When a threat better known as the Joker emerges from his mysterious past and unleashes chaos on Gotham City, Batman must face the greatest of psychological and physical challenges to fight injustice.",
                Actors = new List<Actor>
                {
                    new Actor { Fullname = "Marlon Brando" },
                    new Actor { Fullname = "Al Pacino " },
                }
            });

            context.SaveChanges();
        }
    }
}

Program.cs 코드 추가

  • 이제 EF Core 에서 데이터를 추가할 준비는 모두 완료되었습니다.
  • 마지막으로 MovieApp ASP.NET Core 프로젝트에 있는 Program.cs 에 다음과 같은 코드를 추가합니다.
  • Porgram.cs
using Microsoft.EntityFrameworkCore;
using MovieApp;
using MovieApp.Data;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

builder.Services.AddDbContext<MovieDataContext>(
    o => o.UseNpgsql(builder.Configuration.GetConnectionString("MoviesDb"))
    );

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Seed();
app.Run();

실행 결과

  • 웹 UI 실행 결과, 3개의 데이터가 정상적으로 출력 되어서 보이는 것을 확인할 수 있습니다.


PostgreSQL Database 확인

  • 실제로 Movie, Actor 2개의 Table 에도 정상적으로 데이터가 Insert 되었는지 확인 진행합니다.

Movie Table

  • 정상적으로 데이터가 저장된 것을 확인할 수 있습니다.


Actor Table

  • 정상적으로 데이터가 저장된 것을 확인할 수 있습니다.


728x90

이 글을 공유하기

댓글

Designed by JB FACTORY