在同一 DataContext 執行個體中,**主鍵相同的實體物件只會存在一份** (Identity Cache)。無論查詢多少次,回傳皆為同一參考。
// 實體查詢:主鍵相同 → 同一物件
var c1 = db.Categories.Single(o => o.CategoryId == 1);
var c2 = db.Categories.Single(o => o.CategoryId == 1);
Console.WriteLine(c1 == c2); // True
// 匿名型別投影:無主鍵 → 每次新物件
var a1 = db.Categories.Select(o => new { o.CategoryId, o.CategoryName })
.Single(o => o.CategoryId == 1);
var a2 = db.Categories.Select(o => new { o.CategoryId, o.CategoryName })
.Single(o => o.CategoryId == 1);
Console.WriteLine(a1 == a2); // False
CategoryId=1 → CategoryName="Beverages",物件進入快取。"New Name"。CategoryId=1 → 回傳**快取中舊物件**,CategoryName 仍為 "Beverages"。
db.Refresh(RefreshMode.OverwriteCurrentValues, c2);
// 或 RefreshMode.KeepCurrentValues (保留本地修改,合併伺服器值)
執行後 c2.CategoryName 更新為 "New Name"。
實體類別實作介面,Setter 中呼叫 SendPropertyChanged("PropertyName"),Linq to SQL 透過事件即時得知變更,SubmitChanges 只產生必要 UPDATE SQL。
public string CategoryName {
get { return _CategoryName; }
set {
if (_CategoryName != value) {
OnPropertyChanging("CategoryName");
_CategoryName = value;
OnPropertyChanged("CategoryName");
}
}
}
DataContext 載入實體時建立淺層複製快照。SubmitChanges 時比對目前值與快照值,不同者納入 UPDATE。
缺點:若實體類別實作了 INotifyPropertyChanged 但 Setter **未觸發事件** (如直接賦值 _CategoryName = value),Linq to SQL 會誤判為未變更,**不產生 UPDATE SQL**,導致資料不同步。
因身分識別依賴主鍵,**主鍵值一旦載入不可修改**。嘗試修改主鍵會導致快取索引錯亂、關聯關係破壞。
| 特性 | 實體類別 (有主鍵) | 匿名型別 |
|---|---|---|
| 身分識別快取 | 是 (依主鍵) | 否 |
| 支援 Insert/Update/Delete | 是 | 否 |
| 屬性追蹤 | INotifyPropertyChanged / 快照比對 | 不適用 |
| 跨查詢參考一致性 | 保證 | 不保證 |
掌握身分識別、快取、追蹤三大機制,才能正確使用 Linq to SQL 避免資料不一致、效能浪費與更新遺漏等陷阱。