ClickHouse / ClickHouse/ClickHouse.EntityFrameworkCore

Migrations: split each migration into single-DDL steps (ClickHouse has no transactions)

Đang mở
#44 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
C#
Star
23
Fork
7
Merge trung bình
14 ngày 3 giờ
Pull request đã merge (30 ngày)
1

Mô tả

**Background**

EF Core assumes a migration is atomic: the whole Up() runs inside a transaction, and the row in __EFMigrationsHistory is written only if every operation succeeds. If anything fails, the transaction rolls back and the database is left exactly as it was, so the migration can simply be re-run.

ClickHouse has no transactions for DDL. There is no multi-statement atomicity and no rollback. Each CREATE / ALTER / DROP commits the moment it executes.

The problem

A normal EF migration bundles many DDL operations into one Up():

```protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable("events", /* … */); // DDL_1
migrationBuilder.CreateTable("events_by_day", /* … */); // DDL_2
migrationBuilder.CreateClickHouseMaterializedView( // DDL_3 (depends on DDL_1 + DDL_2)
viewName: "events_mv", targetTable: "events_by_day",
selectQuery: "SELECT day, count() FROM events GROUP BY day");
}
```

EF runs these as a single migration and writes the history row only after DDL_3 succeeds. Now suppose DDL_3 fails (a bad SELECT, an unsupported engine, a transient server error). Because there is no transaction:
- DDL_1 and DDL_2 are already committed: events and events_by_day exist on the server.
- The migration is not recorded as applied (no history row).

The migration is now wedged. Re-running it re-executes DDL_1: CREATE TABLE events → Code: 57. Table already exists. It can never complete, and the database is stuck in a half-applied state that has to be cleaned up by hand.

This is not an edge case, any migration with more than one DDL statement is exposed to it, and the larger the migration the worse the partial-failure blast radius.

Proposed approach: one DDL statement per migration step

Instead of one migration containing N operations, split a single dotnet ef migrations add into N single-operation step migrations, each with its own __EFMigrationsHistory row:
```
20260601120000_Init_001 CREATE TABLE `events` …
20260601120000_Init_002 CREATE TABLE `events_by_day` …
20260601120000_Init_003 CREATE MATERIALIZED VIEW `events_mv` …
```

Now a partial failure is resumable:

- If _003 fails, _001 and _002 are each recorded as applied.
- Fix the model and re-run database update → it skips _001/_002 (already in history) and resumes at _003.

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Hướng nghiên cứu

The issue identifies migration Up(), MigrationBuilder, and __EFMigrationsHistory as the relevant entry points. Start by tracing how the provider executes multiple DDL operations and records migration history. Done means the proposed single-DDL steps preserve ordering and allow a later failed step to resume without re-executing completed steps.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
csharp, sql
Lĩnh vực
backend, databases
Loại issue
Tính năng
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.