Entity Framework 透過 ObjectContext 管理實體生命週期,開發者只需操作實體物件屬性與集合,呼叫 SaveChanges() 即可自動生成對應的 INSERT、UPDATE、DELETE T-SQL 指令。本文系統整理 CRUD 核心操作、關聯實體同步新增、以及刪除時的外鍵約束處理。
using (var context = new NorthwindEntities())
{
// 1. 擷取實體(LINQ to Entities 建議用 First(),SingleOrDefault() 不支援)
var emp = context.Employees.First(e => e.EmployeeID == 1);
if (emp != null)
{
// 2. 修改屬性
emp.City = "San Francisco";
emp.Notes = "New notes for employee 1";
// 3. 儲存變更,回傳受影響實體數
int affected = context.SaveChanges();
Console.WriteLine("異動筆數:" + affected);
}
}
EF 為每個實體型別自動產生 AddTo<EntitySetName> 方法,亦可使用通用 AddObject:
var newEmp = new Employee
{
FirstName = "Jan",
LastName = "Jansen"
// EmployeeID 為 Identity 欄位,由資料庫自動產生,此處無需指定
};
context.AddToEmployees(newEmp); // 或 context.AddObject("Employees", newEmp);
context.SaveChanges();
進階:使用靜態工廠方法建立實體(所有非 Nullable 屬性必須在建構時指定):
// Employee.CreateEmployee(EmployeeID, LastName, FirstName, ...)
var emp = Employee.CreateEmployee(0, "Jansen", "Jan"); // ID 傳 0 佔位
context.AddToEmployees(emp);
context.SaveChanges();
透過導覽屬性集合 .Add() 建立關聯,EF 會依順序生成多條 INSERT 並自動回填外鍵:
var newCat = new Category
{
CategoryName = "Software",
Description = "Software products"
};
// 建立關聯產品
newCat.Products.Add(new Product { ProductName = "Microsoft Visual Studio 2008" });
newCat.Products.Add(new Product { ProductName = "Microsoft Office 2007" });
context.AddToCategories(newCat);
context.SaveChanges();
生成的 T-SQL 批次(簡化):
-- 1. 插入 Category,取回 SCOPE_IDENTITY() 作為 CategoryID
INSERT [dbo].[Categories]([CategoryName], [Description], [Picture])
VALUES (@0, @1, NULL); SELECT [CategoryID] FROM [dbo].[Categories] WHERE @@ROWCOUNT > 0 AND [CategoryID] = scope_identity()
-- 2. 插入 Product 1,自動帶入上一步取得的 CategoryID
INSERT [dbo].[Products]([ProductName], [CategoryID], ...) VALUES (@0, @1, ...)
-- 3. 插入 Product 2,同樣帶入 CategoryID
INSERT [dbo].[Products]([ProductName], [CategoryID], ...) VALUES (@0, @1, ...)
var cat = context.Categories.First(c => c.CategoryName == "Software");
context.DeleteObject(cat); // 或 context.DeleteObject(entityKey)
context.SaveChanges();
常見錯誤: 若資料庫外鍵 FK_Products_Categories 未設定 Cascade Delete,刪除擁有子產品的分類會拋出例外:
"The DELETE statement conflicted with the REFERENCE constraint \"FK_Products_Categories\". The conflict occurred in database \"Northwind\", table \"dbo.Products\", column \"CategoryID\"."

或在程式碼中先手動刪除子實體:
var cat = context.Categories.Include("Products").First(c => c.CategoryName == "Software");
// 先刪除所有關聯產品
foreach (var p in cat.Products.ToList())
context.DeleteObject(p);
context.DeleteObject(cat);
context.SaveChanges();
| 操作 | ObjectContext 方法 | LINQ to SQL 對應 |
|---|---|---|
| 新增 | AddTo<EntitySet>(entity) / AddObject(setName, entity) | Table.InsertOnSubmit(entity) |
| 修改 | 直接修改屬性,SaveChanges() | 直接修改屬性,SubmitChanges() |
| 刪除 | DeleteObject(entity) / DeleteObject(entityKey) | Table.DeleteOnSubmit(entity) |
| 儲存 | SaveChanges() 回傳異動實體數 | SubmitChanges() |
SaveChanges() 以交易方式執行,全部成功或全部回滾。SaveChanges() 後會自動回填至實體屬性。SaveChanges() 或使用 SqlBulkCopy 繞過 EF 以提升效能。掌握這些核心操作模式,即能駕輕就熟地以物件導向方式操作關聯式資料,享受 EF 帶來的開發效率與維護性優勢。