多對多關聯需一張中介表存放雙向外鍵:
CREATE TABLE Blogs (
blog_id int IDENTITY PRIMARY KEY,
blog_name varchar(50),
blog_author varchar(50)
);
CREATE TABLE Communities (
community_id int IDENTITY PRIMARY KEY,
community_name varchar(50),
community_intro varchar(500)
);
CREATE TABLE Blog_Community (
blog_id int NOT NULL,
community_id int NOT NULL,
PRIMARY KEY (blog_id, community_id)
);
在兩端實體各自宣告集合屬性,指向同一中介表:
[ActiveRecord("Blogs")]
public class Blog : ActiveRecordBase {
// ... Id, Name, Author
[HasAndBelongsToMany(typeof(Community),
Table = "Blog_Community",
ColumnKey = "blog_id", // 本端外鍵欄位
ColumnRef = "community_id")] // 對端外鍵欄位
public IList Communities { get; set; }
}
[ActiveRecord("Communities")]
public class Community : ActiveRecordBase {
// ... Id, Name, Intro
[HasAndBelongsToMany(typeof(Blog),
Table = "Blog_Community",
ColumnKey = "community_id",
ColumnRef = "blog_id")]
public IList Blogs { get; set; }
}
三個必要參數:Table(中介表名)、ColumnKey(本端 FK)、ColumnRef(對端 FK)不可省略。
| 屬性 | 說明 | 範例值 |
|---|---|---|
| Cascade | 級聯操作模式 | None / SaveUpdate / Delete / All / AllDeleteOrphan |
| Inverse | 哪一端負責維護關聯(建議一端 true) | true / false |
| Schema | 資料庫 Schema 名稱 | "dbo" |
| Where | 額外 SQL Where 條件 | "IsActive = 1" |
| Lazy | 延遲載入 | true / false |
| 模式 | 行為 |
|---|---|
| None | 不級聯,需手動儲存關聯物件 |
| SaveUpdate | 儲存/更新主體時,自動 Save/Update 關聯物件 |
| Delete | 刪除主體時,自動 Delete 關聯物件(慎用!會刪除對端實體) |
| All | SaveUpdate + Delete |
| AllDeleteOrphan | All + 移除集合中項目時自動刪除該關聯記錄(中介表資料) |
多對多典型設定:Cascade = ManyRelationCascadeEnum.SaveUpdate(只維護中介表關聯,不刪除 Community 實體)。
[Test]
public void TestCascadingSave() {
var blog = new Blog { Name = "Tech Space", Author = "Terrylee" };
blog.Communities = new ArrayList { Community.Find(1), Community.Find(2) };
blog.Save(); // 自動寫入 Blog_Community
}
[Test]
public void TestCascadingUpdate() {
// 從 Blog 端新增關聯
var blog = Blog.Find(10);
blog.Communities.Add(Community.Find(3));
blog.Communities.Add(Community.Find(4));
blog.Save();
// 從 Community 端新增關聯(雙向維護)
var community = Community.Find(3);
community.Blogs.Add(Blog.Find(8));
community.Save();
}
[Test]
public void TestCascadingDelete() {
using (var tran = new TransactionScope()) {
try {
var blog = Blog.Find(10);
blog.Delete(); // 刪除 Blog 及 Blog_Community 關聯記錄
tran.VoteCommit();
} catch { tran.VoteRollBack(); }
}
// 刪除 Community 同理,不會連帶刪除 Blog 實體
}
雙向關聯建議一端設 Inverse = true,表示由另一端負責維護中介表:
[HasAndBelongsToMany(..., Inverse = true)]
public IList Communities { get; set; }
否則雙端 Save 都會嘗試 Insert/Update 中介表,導致重複鍵錯誤或效能浪費。
多對多映射核心在於正確設定中介表三要素(Table, ColumnKey, ColumnRef)與級聯策略。配合 Inverse 避免雙向維護衝突,SaveUpdate 級聯模式滿足多數業務需求。掌握這些設定,即可優雅處理複雜的多對多業務場景。