多对多关系的实现(借助中间关系表)
核心思路
LINQ to SQL 本身只支持一对一和一对多关系,不直接支持多对多。要实现多对多,需要引入第三张关系表,将多对多拆解为两个一对多:
表结构设计
标签表(tag)
CREATE TABLE tag (
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(50) NULL
);Code language: PHP (php)
关系表(relatebooktag)— 拆桥表
CREATE TABLE relatebooktag (
id INT IDENTITY(1,1) PRIMARY KEY,
bid INT NULL,
tid INT NULL,
CONSTRAINT FK_relatebooktag_book FOREIGN KEY (bid) REFERENCES book(id),
CONSTRAINT FK_relatebooktag_tag FOREIGN KEY (tid) REFERENCES tag(id)
);Code language: PHP (php)
关系模型:
┌─────────┐ ┌──────────────────┐ ┌─────────┐
│ book │←── 1:N ─┤ relatebooktag ├─ N:1 → │ tag │
│ │ │ (bid, tid) │ │ │
└─────────┘ └──────────────────┘ └─────────┘Code language: CSS (css)
给书打标签(写入关系数据)
using (var db = new DataClasses1DataContext())
{
// 要打标记的书
var book = db.book.First(m => m.id == 12);
// 准备要打的标签(可能不止一个)
var tags = db.tag.ToList();
// 逐条建立关系
foreach (var item in tags)
{
var tb = new relatebooktag();
tb.book = book; // 设置导航属性,自动赋值 bid
tb.tag = item; // 设置导航属性,自动赋值 tid
db.relatebooktag.InsertOnSubmit(tb);
}
// 一次提交,事务保证
db.SubmitChanges();
}Code language: JavaScript (javascript)
不需要手动赋值外键: 通过
tb.book = book和tb.tag = item,LINQ 自动将book.id和item.id填入bid和tid字段。
查询某本书的所有标签
using (var db = new DataClasses1DataContext())
{
var book = db.book.First(m => m.id == 12);
// 通过关系表的集合导航,逐条取标签名
foreach (var item in book.relatebooktag)
{
Console.WriteLine(book.name + " : " + item.tag.name);
}
}Code language: JavaScript (javascript)
执行逻辑:
book → relatebooktag(一对多,延迟加载)→ tag(一对一,立即加载)
查询某个标签被哪些书使用
using (var db = new DataClasses1DataContext())
{
var tag = db.tag.First(m => m.id == 1);
// 通过关系表的集合导航,逐条取书名
foreach (var item in tag.relatebooktag)
{
Console.WriteLine(tag.name + " : " + item.book.name);
}
}Code language: JavaScript (javascript)
执行逻辑:
tag → relatebooktag(一对多,延迟加载)→ book(一对一,立即加载)
Previous: 一对一关系配置与延迟加载机制
Next: LINQ 中的条件判断(CASE WHEN )