「LINQ查詢變成過程化,無法體現多態」源於對對象-關係映射(ORM)角色的誤解。
// 領域模型(純面向對象)
public abstract class Payment {
public abstract void Process();
}
public class CreditCardPayment : Payment {
public string CardNumber { get; set; }
public override void Process() { /* 信用卡扣款邏輯 */ }
}
public class AlipayPayment : Payment {
public string OpenId { get; set; }
public override void Process() { /* 支付寶扣款邏輯 */ }
}
// EF Core 映射(TPH 表巧層次結構)
public class PaymentEntity {
public int Id { get; set; }
public string Discriminator { get; set; } // "CreditCard" / "Alipay"
public string CardNumber { get; set; }
public string OpenId { get; set; }
}
// LINQ 查詢保持多態語義
var payments = context.Payments
.OfType() // 類型過濾
.Where(p => p.Amount > 1000)
.ToList();
// 多態調用不受影響
foreach (var p in payments) p.Process();
| 傳統SQL | LINQ + 領域模型 |
|---|---|
| 手寫SQL拼接,類型不安全 | 強類型查詢,編譯期檢查 |
| 結果集手動映射對象 | 自動物化領域對象 |
| 業務邏輯分散在SQL/存儲過程 | 業務邏輯封裝在實體方法中 |
| 難以表達繼承/多態關係 | 原生支持TPH/TPT/TPC映射策略 |
// 規約模式封裝查詢邏輯
public class OverduePaymentSpec : Specification {
public override Expression> ToExpression() {
return p => p.DueDate < DateTime.Today && p.Status == PaymentStatus.Pending;
}
}
// 領域服務協調
public class PaymentCollectionService {
public void CollectOverdue() {
var spec = new OverduePaymentSpec();
var overdue = repository.Find(spec); // LINQ 在 Repository 內部執行
foreach (var p in overdue) p.Escalate(); // 多態調用
}
}
LINQ不削弱面向對象,而是通過ORM將關係數據物化為領域對象,使多態、封裝、繼承等OO特性在持久化場景下得以保留。關鍵在於:領域模型驅動設計,LINQ服務於Repository實現細節,而非洩露到業務邏輯層。