출처 : https://code-maze.com/migrations-and-seed-data-efcore/
Database Schemas 관리
EF Core는 EF Core model과 database schema 사이에 sync를 유지하기 위해, 2가지 방법을 제공한다. 둘 중 선택하려면, EF Core model과 database schema 중 기준이 되는 것을 정해야 한다.
EF Core model이 기준이라면, Migrations을 사용해야 한다. EF Core model을 수정하면서 database에도 동일하게 적용해야 한다.
database schema가 기준이라면, Reverse Engineering을 사용한다.
Migration이란?
EF Core를 사용하여 database를 생성하고 업데이트하는 방법이다.
migration에는 2 단계가 있다. migration 생성, migration 적용.
model classes, context class 생성, 구성 적용을 하고 Migrate 함수를 사용하여 Migrations를 실행하면 된다.
- data model이 변경되면 database schema와 sync를 유지하기 위해, EF Core tools을 사용해서 migration을 추가하고 update한다. EF Core는 현재 model과 이전 model의 snapshot을 비교해서 migration source files을 만든다. 이 파일들은 다른 파일들처럼, project의 source control에 의해 track될 수 있다.
- 새로운 migration이 생성되면, database에 적용될 수 있다. EF Core는 적용된 migrations를 특별한 history table에 기록해서, migrations의 적용여부를 알 수 있다.
Creating and Applying Migrations
아래의 EF Core model에 대해 테스트해보자.
public class Student
{
public Guid StudentId { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
migration 생성을 위해서 Visual Studio 의 Package Manager Console창을 사용한다.
MigrationName은 commit message와 같이 사용될 수 있다.
Add-Migration MigrationName [options]
ex) PM> Add-Migration InitialCreate
Actions that Take Place Behind the Scene
Add-Migration을 실행하면 migration 준비를 위한 여러 작업이 이루어진다. 첫번째로 관련된 entity class와 구성을 검사한다. 그 다음 Migration folder에 3가지 다른 파일을 생성한다.
1. AppDbContextModelSnapshot.cs : 신규 migration으로 update할때의 database model을 갖고 있다. 그 다음 migration이 추가되었을 때, 무엇이 변경되었는지를 결정하는 기준이 된다.
2. InitialCreate, InitialCreate.Designer 파일은 신규 migration의 상세 내용을 담고 있다.
Up에는 Migration이 apply되었을 때의 operation을 담고 있고, Down에는 revert되었을 때의 operation을 담고 있다.
파일이름에 있는 timestamp때문에 시간순으로 정렬되고, 변경이력을 볼 수 있다.
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Students",
schema: "dbo",
columns: table => new
{
StudentId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
Age = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Students", x => x.StudentId);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Students",
schema: "dbo");
}
}
Applying Created Migration
migration을 생성했으면, db에 적용을 해야한다.
PM> Update-Database
실행하면 Students 테이블이 생성되었고, 또 하나의 테이블 _EFMigrationsHistory 테이블이 생성된 것을 알 수 있다.
적용된 migrations을 track하는데 사용한다. 각 migration은 SQL transaction과 함께 적용되며, 전체 migration이 성공하거나 실패한다. 여러 migrations을 한번에 적용하면, 생성한 순서대로 적용된다.
Evolving your model
며칠 후, Gender property추가를 요청받았다. model은 아래와 같다.
public class Student
{
public Guid StudentId { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Gender { get; set; }
}
이제 모델과 database의 sync가 맞지 않는다. database schema에 새로운 column을 추가해야 한다.
이를 위해, 새로운 migration을 생성하자.
PM> Add-Migration AddGender
이것이 프로젝트의 첫번째 migration이 아니기 때문에, EF Core는 이제 old model의 snapshot과 updated model을 비교한다. 비교해서, EF Core는 컬럼이 추가되었음을 알아내고, 적합한 migration을 추가한다.
이제 동일한 방식으로, migration을 apply할 수 있다.
PM> Update-Database
Adding a Custom Code in a Migration File
필요하다면, Migration 파일에 custom code를 추가할 수 있다. Sql 함수를 이용해서 custom code를 추가할 수 있다.
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Student",
columns: table => new
{
StudentId = table.Column<Guid>(nullable: false),
Name = table.Column<string>(maxLength: 50, nullable: false),
Age = table.Column<int>(nullable: true),
IsRegularStudent = table.Column<bool>(nullable: false, defaultValue: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Student", x => x.StudentId);
});
migrationBuilder.Sql(@"CREATE PROCEDURE MyCustomProcedure
AS
SELECT * FROM Student");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Student");
migrationBuilder.Sql(@"DROP PROCEDURE MyCustomProcedure");
}
만약에 db를 삭제하는 경우, 단지 이미 만들어진 migration을 다시 apply 하면 된다.
별도의 프로젝트에 Entities, DbContext 파일이 있는 경우 Migration 생성
현재 프로젝트는 model과 context class가 메인프로젝트에 migration files와 함께 있다. 많은 경우에, repository pattern을 적용하며 models, context classes를 별도의 project에 위치한다.
별도의 .NET Core Class Library project인 Entities 프로젝트를 추가해보자.
Entities 프로젝트에 아래 package를 설치한다. context class와 model 파일을 옮겨오고, namespace와 참조 경로등을 수정한다.
main project에 Entities 프로젝트 참조를 추가한다.
builder.Services.AddDbContext<AppDbContext>(option => option.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection"),
options => options.MigrationsAssembly("main project name")));
migrations assembly를 수정한다.
Migration 삭제
DB적용하지 않은 migration을 삭제하는 방법이다.
PM> Remove-Migration
Migration 리스트
기존 migrations 리스트를 조회할 수 있다.
PM> Get-Migration
Application 시작 시, 자동으로 Migration 실행하기
startup동안에, application이 migrations을 적용할 수 있도록 설정할 수 있다. local개발이나, migrations 테스트용으로 적합하다. 다음과 같은 이유로, production DB 관리용으로 적합하지 않다.
- 여러개의 application instance가 돌아가고 있다면, 동시에 migration을 하려고 시도하다가 실패하거나 더 최악의 경우에는 data 변형을 초래할 수 있다.
- 유사하게, 다른 application이 migrate하는 동안, application이 db에 접속할 수 있다.
- application은 db schema를 수정하기 위한 접근권한을 가져야 한다.
- 문제 발생 시, 적용된 migration을 롤백할 수 있는 것은 중요하다. 다른 전략은 이것을 쉽게 제공한다.
- 개발자의 검토 없이 SQL commands가 직접적으로 적용되므로, 운영환경에는 위험하다.
Program.cs
// Migrate latest database changes during startup
using (var scope = app.Services.CreateScope())
{
var dbContext = scope.ServiceProvider
.GetRequiredService<AppDbContext>();
// Here is the migration executed
dbContext.Database.Migrate();
}
app.Run();
Migration 원복하기
DB에 적용한 Migration을 원복하는 방법을 알아보자.
원복할 Migration을 apply해보자.
PM> Add-Migration RevertTestMigration
PM> Update-Database
RevertTestMigration 이전으로 돌아가기 위해서, 직전 Migration을 apply한다.
PM> Update-Database Refresh
EFMigrationHistory에 RevertTestMigration 내역이 삭제되었고, DB도 이전으로 돌아갔다.
20230609081652_RevertTestMigration.cs 파일은 삭제되지 않는다.
모든 Migration을 SQL script로 만드는 방법
모든 Migration을 SQL script로 만드는 방법
PM> Script-Migration
자동으로 script file이 생성된다.
'Entity Framework Core' 카테고리의 다른 글
Entity Framework Core] Loading pattern (0) | 2023.07.14 |
---|---|
Entity Framework Core] .AsNoTracking()이란? (0) | 2023.06.09 |
ASP.NET Core] Entity Framework Core - database model 구성방법 (0) | 2023.05.23 |
ASP.NET Core] Entity Framework Core란? (1) | 2023.05.23 |
ASP.NET Core] Entity Framework Core - SQL Queries (0) | 2023.05.09 |
댓글