Entity Framework Core의 In-Memory 데이터베이스에 초기 데이터 입력

소개



테스트나 환경을 더럽히지 않기 위해 In-Memory 데이터베이스를 사용할 때 초기 데이터를 입력하는 방법을 조사했습니다.

데이터베이스 컨텍스트의 OnModelCreating 메서드에 후크하여 초기화합니다.OnModelCreating는 데이터베이스 컨텍스트가 초기화 될 때 한 번만 호출됩니다.
HasData 메서드 초기화는 Entity Framework Core에서 ID의 자동 설정을 수행하지 않습니다.
따라서 직접 ID 를 가져와야 합니다.
public DbSet<Book> Books { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder) =>
  modelBuilder.Entity<Book>().HasData(
    new Book { ID = 1, Name = "アンドロイドは電気羊の夢を見るか?" },
    new Book { ID = 2, Name = "幼年期の終り" },
    new Book { ID = 3, Name = "一九八四年" }
);

샘플 앱 In-Memory 데이터베이스를 사용한 Web API



프로젝트의 병아리 만들기


# テンプレートには Web API を選択
$ dotnet new webapi -n SeedingInMemoryDb
$ cd SeedingInMemoryDb
# In-Memory データベースを使うためにライブラリをインストール
$ dotnet add Package Microsoft.EntityFrameworkCore.InMemory

모델 및 데이터베이스 컨텍스트



Models/Books.cs
public class Book {
  public int ID { get; set; }
  public string Name { get; set; }
}
// using Microsoft.EntityFrameworkCore;
// using SeedingInMemoryDb.Models;

public class SampleInMemoryDbContext : DbContext {
  public SampleInMemoryDbContext(DbContextOptions options) : base(options) { }

  public DbSet<Book> Books { get; set; }

  protected override void OnModelCreating(ModelBuilder modelBuilder) =>
    modelBuilder.Entity<Book>().HasData(
      new Book { ID = 1, Name = "アンドロイドは電気羊の夢を見るか?" },
      new Book { ID = 2, Name = "幼年期の終り" },
      new Book { ID = 3, Name = "一九八四年" }
    );
}


Startup 클래스



In-Memory 데이터베이스를 사용하도록 설정합니다.
언제나처럼 AddDbContext 때 옵션에서 UseInMemoryDatabase 메서드를 호출합니다.UseInMemoryDatabase 메소드 인수의 데이터베이스 이름은 필수입니다.

Startup.cs
// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.DependencyInjection;

public void ConfigureServices(IServiceCollection services) {
  services.AddDbContext<SampleInMemoryDbContext>(options => 
    options.UseInMemoryDatabase("sample_in_memory_db");
  );
  services.AddControllers();
}

진입점



In-Memory 데이터베이스를 구축하고 초기 데이터를 입력합니다.
Program.cs DI 컨테이너가 아직 구성되기 전에 데이터베이스 컨텍스트를 DI 수 없습니다.
서비스 프로바이더로부터 인스턴스를 취득해 EnsureCreatedAsync 메소드를 호출해 DB 를 작성합니다.

Program.cs
// using Microsoft.AspNetCore.Hosting;
// using Microsoft.Extensions.DependencyInjection;
// using Microsoft.Extensions.Hosting;
// using System.Threading.Tasks;

public class Program {
  public static async Task Main(string[] args) {
    IHost host = BuildHost(args);
    using IServiceScope scope = host.Services.CreateScope();
    IServiceProvider provider = scope.ServiceProvider;
    using var context = provider.GetRequiredService<SampleInMemoryDbContext>();
    await context.Database.EnsureCreatedAsync();
    host.Run();
  }

  public static IHost BuildHost(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(web => web.UseStartup<Startup>()
        .Build();
}

컨트롤러 클래스



In-Memory 데이터베이스의 모든 책을 반환하는 엔드포인트 /api/books를 만들어 봅니다.

Controllers/BooksController.cs
// using Microsoft.AspNetCore.Mvc;
// using Microsoft.EntityFrameworkCore;
// using SeedingInMemoryDb.Models;
// using System.Collections.Generic;
// using System.Threading.Tasks;

[Route("api/[controller]")]
public class BooksController : Controller {
  private readonly SampleInMemoryDbContext _db;
  public BooksController(SampleInMemoryDbContext db) => _db = db;

  [HttpGet]
  public async Task<ActionResult<IEnumerable<Book>>> Get() =>
    await _db.Books.ToListAsync();
}

실행 결과



실행 localhost:{ポート番号}/api/books 에 액세스합니다.
In-Memory 데이터베이스에 초기 데이터가 투입되어, 그 데이터를 전건 취득할 수 있는 것을 확인할 수 있었습니다.


실행 환경은 다음과 같습니다.
  • Windows X64
  • Visual Studio 2019 (v16.4)
  • .NET Core SDK 3.1.101
  • C# 8.0
  • 좋은 웹페이지 즐겨찾기