Migration: MSSQL → PostgreSQL
Mục tiêu: đồng nhất cơ sở dữ liệu về PostgreSQL. Cách tiếp cận chưa chốt — Dev sẽ review 3 hướng: sửa trực tiếp / lớp cấu hình / tách source khác. Trang này cung cấp số liệu để ra quyết định đó.
Phạm vi đo được (từ source thật)
| Hạng mục | Giá trị | Ghi chú |
|---|---|---|
| Số DB vật lý | 1 (SOEZY_DESEARCHDB_DEV) | "SoEzyEntities" và "SOEZY_REPORT_DB" là tên context, không phải 2 DB |
| Stack data-access | 2 khác nhau | Worker: EF6 EDMX (database-first). API: EF Core 5 code-first scaffold |
| EDMX | Có — SoEzyEntities.edmx 161KB / 2123 dòng | Provider System.Data.SqlClient, token SQL2012, nhúng làm build resource |
| Raw SQL trong source | 2 call site | Cả hai trong SystemExceptionSendWarningEmailEngine.cs |
| Stored procedure | 3 (JSON-in/JSON-out) | Body nằm trong DB, không có trong repo |
| Script DDL tay | 4 file .sql | Chỉ phủ 4 bảng mới nhất |
| Số entity/bảng | ~25–28 (worker EDMX) / 26 DbSet (API) | API là tập khác/giao, không trùng khít |
| Migration code-managed? | Không | Không có thư mục EF Migrations; schema sống trong DB thật |
Hai stack — hai cách migrate
Worker (DE_Searches) | API (DE_Searches_API_NetCore) | |
|---|---|---|
| ORM | EF6 EDMX database-first | EF Core 5 code-first scaffold (UseSqlServer) |
| Framework | net4.5.2 | net5.0 |
| Provider Postgres | Không có EF6 Npgsql production trên net4.x → buộc re-platform sang EF Core/Npgsql | Npgsql.EntityFrameworkCore.PostgreSQL (đổi UseSqlServer→UseNpgsql) |
| Độ khó | Cao (kèm retarget framework) | Trung bình (nhưng vướng DLL Ezy.*) |
3 hướng tiếp cận để Dev review
Hướng A — Sửa trực tiếp (in-place)
Đổi provider tại chỗ: API UseSqlServer→UseNpgsql; worker bỏ EDMX, scaffold lại từ Postgres.
- Ưu: ít kiến trúc mới, một codebase.
- Nhược: đụng ngay DLL
Ezy.*.MSSQL(không recompile được); worker phải retarget net8 + bỏ EDMX cùng lúc → rủi ro cao.
Hướng B — Lớp cấu hình (provider abstraction + flag)
Trừu tượng hoá provider, chọn MSSQL/Postgres qua config; chạy song song để so sánh.
- Ưu: rollback dễ, migrate dần từng bảng/từng context.
- Nhược: EF6 EDMX rất khó nhét sau abstraction; vẫn kẹt DLL
Ezy.*.
Hướng C — Tách source khác (data-access service mới)
Viết lớp data-access mới trên EF Core/Npgsql (.NET 8), cả worker lẫn API gọi qua đó, loại dần DLL Ezy.*.
- Ưu: thoát hẳn binary MSSQL closed-source; thống nhất 1 stack.
- Nhược: công lớn nhất; phải dựng lại repository/bulk/stored-proc layer.
Gợi ý: nếu DLL
Ezy.*không có bản Postgres từ vendor thì Hướng C gần như bắt buộc cho phần worker, vì A/B đều không vượt được binary MSSQL.
Đầu việc lớn (epics)
EPIC 0 — Quyết định & chuẩn bị
- Liên hệ vendor: có bản Postgres của
Ezy.Module.BaseMSSQLData/MSSQLRepository/EzyEFStoreRepositorykhông? Verify: câu trả lời rõ ràng có/không (chốt được hướng A/B vs C). - Trích full schema từ DB thật (không chỉ 4 script DDL). Verify: dump đầy đủ ~25+ bảng.
- Chốt cách map
ROWVERSION(xmin vs trigger). Verify: POC 1 bảng có concurrency token chạy được trên Postgres.
EPIC 1 — Schema → PostgreSQL
- Chuyển DDL:
IDENTITY(1,1)→GENERATED AS IDENTITY,NVARCHAR(MAX)→text,datetime→timestamp,[dbo].[x]→identifier thường,ROWVERSION→giải pháp đã chốt. Verify: tạo schema rỗng chạy được trên Postgres. - Viết 3 stored proc JSON-in/JSON-out lại dạng function Postgres (hoặc chuyển vào app code). Verify: so output JSON với proc MSSQL cũ.
EPIC 2 — API (.NET 5, dễ hơn)
- Thêm
Npgsql.EntityFrameworkCore.PostgreSQL, đổiUseSqlServer→UseNpgsql. Verify: API CRUD chạy trên Postgres. - Xử lý
Z.EntityFramework.Extensions(bulk) — cần build/giấy phép hỗ trợ Postgres. Verify: bulk insert chạy. - Thay
System.Data.SqlClientở các raw call → Npgsql. Verify: 2 call site engine email chạy.
EPIC 3 — Worker (.NET Framework, khó nhất)
- Re-platform data layer EF6 EDMX → EF Core/Npgsql (phụ thuộc EPIC retarget bên Playwright). Verify: 1 worker đọc/ghi
TextSearch_*trên Postgres. - Thay/loại các DLL
Ezy.*.MSSQLtheo hướng đã chốt. Verify: không còn ref binary MSSQL.
EPIC 4 — Dữ liệu & cutover
- Công cụ chuyển data MSSQL→Postgres (pgloader / script). Verify: đếm dòng + checksum khớp.
- Test song song (dual-write hoặc so đọc). Verify: kết quả khớp giữa 2 DB.
3 thứ khó nhất (đã xác nhận từ source)
ROWVERSION/TimeStampconcurrency token trên MỌI bảng — Postgres không có tương đương; phải remap sangxminhoặc cột trigger trên ~50 bảng và test lại toàn bộ hành vi concurrency của EF.- EF6 EDMX gắn chặt SqlClient SSDL — không có EF6 Npgsql production trên net4.5.2; thực tế phải re-platform toàn bộ worker data layer sang EF Core/Npgsql (kéo theo việc port .NET Framework → .NET hiện đại).
- DLL
Ezy.*.MSSQLclosed-source — connection, bulk-ops, stored-proc nhúng trong binary không recompile được; cần bản Postgres từ vendor hoặc viết lớp thay thế; 3 stored proc (không có trong repo) phải viết lại.
Rủi ro & lưu ý
- Credential DB plaintext ở 3+ nơi (
Core/App.config,App_Data/Setting.txt, hardcode trongCategories.SOEZY_DESEARCHDB_DEVModel.cs) → xử lý cùng lúc khi đổi connection string. - Connection string stored-proc lại nằm trong một bảng DB (
ConfigStoreProcedure4Reports) → đừng bỏ sót. - Schema phần lớn chỉ tồn tại trong DB thật, không trong repo → phải dump trước khi làm gì.
- API DbSet và worker EDMX là tập khác nhau → migrate phải gộp/đối chiếu, không copy 1-1.