it

C# Entity Framework Zero Downtime Deployment

c entity framework zero downtime deployment
C# Entity Framework Zero Downtime Deployment

C# Entity Framework Zero Downtime Deployment คืออะไร

C# Entity Framework Zero Downtime Deployment

Entity Framework (EF) Core เป็น ORM (Object-Relational Mapper) หลักของ .NET ที่ช่วย developers ทำงานกับ database ผ่าน C# objects แทนการเขียน SQL โดยตรง Zero Downtime Deployment คือการ deploy application version ใหม่โดยไม่มี downtime — ผู้ใช้ไม่รู้สึกว่าระบบหยุดทำงาน ความท้าทายหลักคือ database migrations ที่ต้อง backward compatible เพราะระหว่าง deploy มีทั้ง version เก่าและใหม่ทำงานพร้อมกัน บทความนี้อธิบายวิธี deploy EF Core applications แบบ zero downtime พร้อมตัวอย่าง code

EF Core Migration Best Practices

# ef_migrations.py — EF Core migration patterns for ZDT import json class EFMigrationPatterns: SAFE_OPERATIONS = """ // === SAFE Operations (backward compatible) === // 1. ADD column (nullable or with default) migrationBuilder.AddColumn( name: "MiddleName", table: "Users", type: "nvarchar(100)", nullable: true); // nullable = safe // 2. ADD table migrationBuilder.CreateTable( name: "UserPreferences", columns: table => new { Id = table.Column(nullable: false) .Annotation("SqlServer:Identity", "1, 1"), UserId = table.Column(nullable: false), Theme = table.Column(maxLength: 50, nullable: true), }); // 3. ADD index (CONCURRENTLY on PostgreSQL) migrationBuilder.CreateIndex( name: "IX_Users_Email", table: "Users", column: "Email"); // 4. RENAME via expand-contract pattern // Step 1 (deploy v1.1): Add new column migrationBuilder.AddColumn( name: "FullName", table: "Users", nullable: true); // Step 2 (deploy v1.2): Copy data + use new column // Step 3 (deploy v1.3): Drop old column """ UNSAFE_OPERATIONS = """ // === UNSAFE Operations (cause downtime) === // ❌ DROP column — old version still reads it migrationBuilder.DropColumn(name: "OldField", table: "Users"); // ❌ RENAME column — old version can't find it migrationBuilder.RenameColumn( name: "Name", table: "Users", newName: "FullName"); // ❌ Change column type — may lose data migrationBuilder.AlterColumn( name: "Age", table: "Users", type: "int"); // ❌ Add NOT NULL column without default migrationBuilder.AddColumn( name: "RequiredField", table: "Users", nullable: false); // Old version inserts without this field → error! """ def show_safe(self): print("=== Safe Operations ===") print(self.SAFE_OPERATIONS[:600]) def show_unsafe(self): print("\n=== Unsafe Operations ===") print(self.UNSAFE_OPERATIONS[:500]) patterns = EFMigrationPatterns() patterns.show_safe() patterns.show_unsafe()

Expand-Contract Pattern

C# Entity Framework Zero Downtime Deployment
# expand_contract.py — Expand-Contract migration pattern import json class ExpandContractPattern: PATTERN = """ // === Expand-Contract Pattern for Column Rename === // Goal: Rename "Name" → "FullName" without downtime // === Phase 1: EXPAND (Deploy v2.0) === // Add new column, keep old column public partial class AddFullNameColumn : Migration { protected override void Up(MigrationBuilder migrationBuilder) { // Add new column (nullable) migrationBuilder.AddColumn( name: "FullName", table: "Users", type: "nvarchar(200)", nullable: true); // Copy existing data migrationBuilder.Sql( "UPDATE Users SET FullName = Name WHERE FullName IS NULL"); // Add trigger to sync (optional) migrationBuilder.Sql(@" CREATE TRIGGER trg_SyncFullName ON Users AFTER INSERT, UPDATE AS BEGIN UPDATE u SET u.FullName = i.Name FROM Users u INNER JOIN inserted i ON u.Id = i.Id WHERE u.FullName IS NULL OR u.FullName != i.Name END"); } } // App v2.0: Read from FullName, write to BOTH Name + FullName // Old app v1.x: Still reads/writes Name — works fine // === Phase 2: MIGRATE (Deploy v2.1) === // App reads/writes only FullName // Verify all data migrated // === Phase 3: CONTRACT (Deploy v2.2) === public partial class DropNameColumn : Migration { protected override void Up(MigrationBuilder migrationBuilder) { // Drop trigger migrationBuilder.Sql("DROP TRIGGER IF EXISTS trg_SyncFullName"); // Drop old column (safe — no app reads it anymore) migrationBuilder.DropColumn(name: "Name", table: "Users"); } } """ TIMELINE = [ "Deploy v2.0: Add FullName column + sync trigger (old app works)", "Deploy v2.1: App uses FullName only (old column still exists)", "Verify: All data migrated, no reads on old column", "Deploy v2.2: Drop old Name column + trigger (cleanup)", ] def show_pattern(self): print("=== Expand-Contract Pattern ===") print(self.PATTERN[:600]) def show_timeline(self): print(f"\n=== Deployment Timeline ===") for step in self.TIMELINE: print(f" → {step}") ec = ExpandContractPattern() ec.show_pattern() ec.show_timeline()

FAQ - คำถามที่พบบ่อย

Q: EF Migration ต้อง run ก่อน deploy app ใหม่หรือเปล่า?

A: ใช่ — ต้อง migrate database ก่อน deploy app version ใหม่ เพราะ: app ใหม่อาจต้องการ columns/tables ใหม่ที่ migration สร้าง ลำดับ: 1) Apply migration → 2) Deploy new app → 3) Old app ยัง run ได้ (backward compatible) สำคัญ: migration ต้อง backward compatible — old app version ต้อง work กับ schema ใหม่ได้

เนื้อหาเกี่ยวข้อง — อ่านต่อ: Azure Functions Message Queue Design

Q: ถ้า migration ผิดพลาด rollback ยังไง?

แนะนำเพิ่มเติม — XM Signal

A: EF Core: dotnet ef database update [PreviousMigrationName] — rollback ไป migration ก่อนหน้า แต่: ถ้า migration ทำ data transformation — rollback อาจสูญเสียข้อมูล Best practice: backup database ก่อน migrate เสมอ ป้องกัน: test migration บน staging ก่อน production + ใช้ expand-contract pattern

เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง PostgreSQL JSONB Monitoring และ Alerting — คู่มือฉบับสมบูรณ์ 2026

Q: Expand-Contract ต้องใช้กี่ deploys?

A: ขั้นต่ำ 3 deploys: Deploy 1 (Expand): เพิ่ม column ใหม่ + sync data Deploy 2 (Migrate): app ใช้ column ใหม่เท่านั้น Deploy 3 (Contract): ลบ column เก่า ข้อเสีย: ช้ากว่า deploy เดียว แต่ไม่มี downtime เลย เหมาะกับ: production systems ที่ downtime ยอมรับไม่ได้

แนะนำเพิ่มเติม — เรียนเทรดกับ iCafeForex

เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน OPA Gatekeeper Database Migration

Q: EF Core กับ Dapper อันไหนดีสำหรับ ZDT?

A: EF Core: มี migration system built-in, schema ผูกกับ model — เปลี่ยน model = ต้อง migrate Dapper: ไม่มี migration (ใช้ FluentMigrator/DbUp แทน), SQL เขียนเอง — flexible กว่า สำหรับ ZDT: ทั้งสองทำได้ — สำคัญคือ migration strategy ไม่ใช่ ORM EF Core ง่ายกว่า: migration tooling ดี, model-first approach Dapper ยืดหยุ่นกว่า: ควบคุม SQL ได้เต็มที่

เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน จอมอนิเตอร์ 2k — ทุกสิ่งที่ต้องรู้ในปี 2026

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง