마이그레이션
형식이 바뀔 때 표도 함께 바꿉니다.
표가 이미 자료를 담고 있습니다
3.1에서 EnsureCreated() 로 표를 만들었습니다. 없으면
만들고 있으면 그냥 둡니다. 형식이 바뀌어도 표는 바뀌지 않습니다.
처음 배울 때는 지우고 다시 만들면 되지만, 운영 중인 데이터베이스에서는 그럴 수
없습니다.
마이그레이션은 바뀐 만큼만 적용하는 방법입니다. 형식을 고칠 때마다 무엇이 달라졌는지를 코드 파일로 남기고, 데이터베이스에는 아직 적용하지 않은 것만 순서대로 적용합니다.
그 코드 파일은 저장소에 함께 담습니다. 그래야 다른 사람의 기계와 운영 서버가 같은 순서로 같은 것을 적용합니다.
첫 마이그레이션 만들기
명령 도구를 먼저 갖춥니다. 프로젝트에는 Design 패키지가 필요합니다.
dotnet tool install --global dotnet-ef dotnet add package Microsoft.EntityFrameworkCore.Design dotnet ef migrations add 첫판
이 단원의 명령은 브라우저가 아니라 여러분의 터미널에서 돌립니다.
앞의 숫자는 만든 시각입니다. 이것이 적용 순서를 정합니다. 여러 사람이 각각 만들어도 시각으로 줄이 세워집니다.
가운데 파일이 실제로 하는 일입니다.
protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Todos", columns: table => new { Id = table.Column<int>(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Title = table.Column<string>(type: "TEXT", nullable: false), Done = table.Column<bool>(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_Todos", x => x.Id); }); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable(name: "Todos"); }
아직 데이터베이스는 바뀌지 않았습니다. 파일만 만들어졌습니다. 적용은 따로 합니다.
적용하기
적용하는 방법이 둘입니다. 개발 기계에서는 명령으로, 앱 안에서는
Migrate() 로 합니다.
# 터미널에서 dotnet ef database update // 또는 앱이 뜰 때 await db.Database.MigrateAsync();
적용한 것을 데이터베이스가 기억합니다. __EFMigrationsHistory 라는 표가 그 자리입니다. 첫 적용 때 함께 만들어집니다.
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" ( "MigrationId" TEXT NOT NULL CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY, "ProductVersion" TEXT NOT NULL ); BEGIN TRANSACTION; CREATE TABLE "Todos" (…); INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('20260829151044_첫판', '10.0.11'); COMMIT; BEGIN TRANSACTION; ALTER TABLE "Todos" ADD "Priority" INTEGER NOT NULL DEFAULT 0; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('20260829151108_중요도추가', '10.0.11'); COMMIT;
운영에는 이 스크립트를 사용하는 편이 안전합니다. 앱이 뜰 때
Migrate() 를 부르면 편하지만, 서버가 여럿이면 동시에
부르게 되고 무엇이 적용될지 미리 볼 수 없습니다. 스크립트를 뽑아 두면
사람이 읽고 승인한 뒤 적용할 수 있습니다.
# 지금 적용된 것부터 마지막까지 dotnet ef migrations script --idempotent -o deploy.sql # 무엇이 아직 적용되지 않았는지 보기 dotnet ef migrations list
20260829151044_첫판 20260829151108_중요도추가 (Pending) 20260829151121_이름바꾸기 (Pending)
무엇을 고쳤느냐에 따라 다릅니다
형식을 고치고 migrations add 를 부르면, EF Core 가
지난번 사진과 비교해 달라진 것을 알아냅니다. 세 가지를 고쳐
보았습니다.
| 고친 것 | 만들어진 것 |
|---|---|
| 속성 추가 | AddColumn — 이미 있는 줄에는 기본값이 들어갑니다 |
| 속성 이름 변경 | RenameColumn — 값이 그대로 옮겨 갑니다 |
| 속성 형식 변경 | AlterColumn |
// int Priority 를 더했을 때 migrationBuilder.AddColumn<int>( name: "Priority", table: "Todos", type: "INTEGER", nullable: false, defaultValue: 0); // Title 을 Subject 로 바꿨을 때 migrationBuilder.RenameColumn( name: "Title", table: "Todos", newName: "Subject"); // Priority 를 int 에서 string 으로 바꿨을 때 migrationBuilder.AlterColumn<string>( name: "Priority", table: "Todos", type: "TEXT", nullable: false, oldClrType: typeof(int), oldType: "INTEGER");
만들어진 파일을 반드시 열어 보십시오. 알아내지 못하는 경우가
있습니다. 이름을 바꾸면서 형식도 함께 바꾸거나, 여러 속성을 한꺼번에 손대면
DropColumn 과 AddColumn 이
나올 수 있습니다. 그러면 그 칸의 자료가 사라집니다. 그때는
손으로 RenameColumn 으로 고쳐 적습니다.
이름을 바꾸는 마이그레이션은 따로 하나로 만드는 편이 안전합니다. 다른 변경과 섞이지 않으면 알아내기 쉽습니다.
적용한 뒤에는 고치지 않습니다
아직 적용하지 않은 마이그레이션은
dotnet ef migrations remove 로 지우고 다시
만들면 됩니다. 그런데 이미 다른 사람의 기계나 운영에 적용된 것은
고치지 마십시오. 기록 표에는 그 이름이 적용된 것으로 남아 있어,
내용을 바꿔도 다시 적용되지 않습니다.
고쳐야 한다면 새 마이그레이션을 하나 더 만듭니다. 되돌려야
한다면 dotnet ef database update 앞의이름 으로
그 지점까지 Down 을 적용합니다.
직접 해보기
DateOnly? Due 를 더하고 마이그레이션을 만들어
적용해보세요. 이미 담긴 줄에는 무엇이 들어갈지 먼저 짐작해보십시오.
방금 적용한 것을 되돌리고, 마이그레이션 파일도 지우려면 어떤 명령을 어떤 순서로 부를지 적어보세요.
string Title 을
string Subject 로 바꾸면서 동시에
int Priority 도 지웠습니다. 만들어진 파일에서
무엇을 확인해야 하는지와, 잘못 나왔다면 어떻게 고칠지
적어보세요.
- 마이그레이션은 바뀐 만큼만 적용해 이미 담긴 자료를 지킵니다.
migrations add는 파일만 만듭니다. 적용은database update입니다.- 적용한 것은 __EFMigrationsHistory 에 기록되고, 마이그레이션 하나가 트랜잭션 하나입니다.
- 만들어진 파일을 열어 보십시오. 이름 변경이 지우고 다시 만드는 것으로 나오면 자료가 사라집니다.
- 이미 적용된 마이그레이션은 고치지 않고 새로 하나 더 만듭니다.