🧾EF Core:Fluent API 與 Data Annotations 有什麼不同?一篇就搞懂(含範例與選用指南)
- 取得連結
- X
- 以電子郵件傳送
- 其他應用程式
內容
想把 C# 類別正確對應到資料庫表(Code-First),你一定會遇到 Data Annotations 與 Fluent API。這兩者其實都是在做「模型組態」(Model Configuration):也就是告訴 EF Core 你的類別如何對映到資料表。差別在於「寫法位置」與「可表達能力」。
TL;DR(先給結論)
-
Data Annotations:直接在類別/屬性貼 Attribute(如
[Key],[Required],[MaxLength])。上手快、就地可讀,但表達力有限。 -
Fluent API:在
OnModelCreating或IEntityTypeConfiguration<T>裡用鏈式語法設定。最完整、可抽離、可維護,適合中大型專案。 -
衝突優先序:慣例 < Data Annotations < Fluent API(Fluent 會覆蓋註解)。
什麼是 Data Annotations?
把規則貼在模型本身,例如必填、長度、欄位型別、索引等。可讀性高、看檔案就知道欄位規則。
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("CUSTOMERS")]
public class Customer
{
[Key]
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; } = string.Empty;
[Column(TypeName = "varchar(50)")]
public string? Email { get; set; }
public ICollection<Order> Orders { get; set; } = new List<Order>();
}
[Table("ORDERS")]
public class Order
{
[Key]
public int Id { get; set; }
[Required]
public DateTime CreatedAt { get; set; }
public int CustomerId { get; set; }
[ForeignKey(nameof(CustomerId))]
public Customer Customer { get; set; } = null!;
}
小提醒:EF Core 也提供
[Index],[Precision]等新特性,但複合鍵、刪除行為、擁有型別(Owned Types)、全域查詢篩選等進階設定,還是建議用 Fluent API。
什麼是 Fluent API?
把組態集中在一處(OnModelCreating
或分檔
IEntityTypeConfiguration<T>):
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class CustomerConfig : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> b)
{
b.ToTable("CUSTOMERS");
b.HasKey(x => x.Id);
b.Property(x => x.Name)
.IsRequired()
.HasMaxLength(100);
b.Property(x => x.Email)
.HasColumnType("varchar(50)");
b.HasIndex(x => x.Email).IsUnique();
b.HasMany(x => x.Orders)
.WithOne(x => x.Customer)
.HasForeignKey(x => x.CustomerId)
.OnDelete(DeleteBehavior.Restrict);
}
}
public class OrderConfig : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> b)
{
b.ToTable("ORDERS");
b.HasKey(x => x.Id);
b.Property(x => x.CreatedAt).IsRequired();
}
}
public class AppDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new CustomerConfig());
modelBuilder.ApplyConfiguration(new OrderConfig());
}
}
只有 Fluent 才好寫的事:
-
複合主鍵:
b.HasKey(x => new { x.Sku, x.Site }); -
進階關聯與刪除行為:
OnDelete(DeleteBehavior.Restrict/Cascade/NoAction) -
擁有型別(Value Object):
b.OwnsOne(...) -
欄位轉換:
HasConversion()(enum↔字串/數值、JSON、逗號字串等) -
全域查詢篩選:
HasQueryFilter(x => !x.IsDeleted) -
預設值/計算欄位 SQL:
HasDefaultValueSql(...)、HasComputedColumnSql(...)
快速比較表
| 面向 | Data Annotations | Fluent API |
|---|---|---|
| 可表達能力 | 基本欄位/索引/必要性/長度 | 幾乎全部(關聯、刪除行為、複合鍵、擁有型別、轉換、全域篩選…) |
| 可讀性 | 規則貼在類別上,一眼可見 | 規則集中、乾淨,結構化管理 |
| 關注點分離 | 較弱(模型與對映耦合) | 較強(可分檔、可重用) |
| 複雜關聯 | 受限/不便 | 直覺完整 |
| 跨專案重用 | 不易 |
容易(IEntityTypeConfiguration<T>)
|
| 衝突時優先序 | 慣例 < 註解 | Fluent 最高,會覆蓋註解 |
我應該選哪個?
-
小型/快速原型:以 Data Annotations 為主,省時、直覺。
-
中大型/多表關聯/長期維護:以 Fluent API 為主,彈性最大、可抽離組態。
-
混合策略(常見實務):
-
基礎屬性(
[Required],[MaxLength],[Index])用註解保留就地可讀; -
關聯、複合鍵、刪除行為、轉換、Owned Types、Query Filter等用 Fluent 集中管理。
-
有衝突時,以 Fluent 為準。
-
進階小範例(抄了就能用)
1) 複合鍵+唯一索引
b.HasKey(x => new { x.Site, x.Sku });
b.HasIndex(x => new { x.Site, x.Sku, x.Week }).IsUnique();
2) Enum ↔ 字串轉換
b.Property(x => x.Status)
.HasConversion<string>() // Enum 存字串
.HasMaxLength(20)
.IsRequired();
3) 擁有型別(Value Object)
b.OwnsOne(x => x.Address, a =>
{
a.Property(p => p.City).HasMaxLength(50);
a.Property(p => p.Zip).HasMaxLength(10);
});
4) 全域查詢篩選(軟刪除)
modelBuilder.Entity<Customer>() .HasQueryFilter(c => !c.IsDeleted);
5) 預設值與計算欄位
b.Property(x => x.CreatedAt)
.HasDefaultValueSql("CURRENT_TIMESTAMP");
b.Property(x => x.Total)
.HasComputedColumnSql("[UnitPrice]*[Qty]");
若使用 Oracle、PostgreSQL 等,記得把
HasColumnType(...)及 SQL 片段改成對應資料庫語法。
常見陷阱與最佳實務
-
把所有規則都塞進模型 → 長期會變得難維護。建議進階設定集中到 Fluent。
-
跨檔案/跨專案重用 → 用
IEntityTypeConfiguration<T>把組態拆檔,未來擴充更容易。 -
命名/型別差異 → 明確指定
HasColumnType、長度與精度(如HasPrecision(18, 4))。 -
刪除行為 → 預設可能是
Cascade;重要資料建議明確指定Restrict或NoAction。 -
衝突時誰說了算 → 記得 Fluent > Data Annotations > 慣例。
結語
Data Annotations 讓你快速上手、文件化欄位規則;Fluent API 則提供完整控制與可維護結構。實務上很常「混搭」:簡單規則留在模型,複雜對映集中到 Fluent。掌握這個分工,你的 EF Core 專案會更乾淨、穩定,也更容易交接維護。
- 取得連結
- X
- 以電子郵件傳送
- 其他應用程式
留言
張貼留言