這一節的內容是在離線場景中保存實體和實體圖集html
在離線場景中,當咱們保存一個離線的實體圖集或一個單獨的離線實體時,咱們須要作兩件事。首先,咱們要把實體附加到新的上下文中,讓上下文了知道存在這些實體。其次,咱們須要手動設置每一個實體的EntityState,由於新的上下文不知道這些離線實體都通過了些什麼操做,因此新的上下文不能自動地給實體添加EntityState。上一節咱們清楚了附加離線圖集的方法,附加離線圖集時默認添加的EntityState不必定合適,因此咱們就要執行第二步:給實體或實體圖集添加合適的EntityState。sql
在離線場景中咱們保存一個實體時,最核心的問題:咱們須要知道一個實體是新建的仍是原本就存在的。只有知道了這個問題的答案,咱們才能給實體設置EntityState。若是實體主鍵值是0(主鍵是Int類型,默認值爲0)咱們認爲這個實體是新建的,給它的狀態標記爲Added;若是主鍵值大於0,那麼咱們就認爲這個實體是已經存在的,將它的狀態標記爲Modified。以下圖所示:數據庫
下邊是一個栗子:ide
// 新建的離線實體 var student = new Student(){ StudentName = "Bill" }; using (var context = new SchoolDBEntities()) { context.Entry(student).State = student.StudentId == 0? EntityState.Added : EntityState.Modified; context.SaveChanges(); }
由於Student是新建的,Id默認爲0,因此Student被標記爲Added,在數據庫中執行:post
exec sp_executesql N'INSERT [dbo].[Student]([StudentName], [StandardId]) VALUES (@0, NULL) SELECT [StudentID] FROM [dbo].[Student] WHERE @@ROWCOUNT > 0 AND [StudentID] = scope_identity(),@0='Bill'
一樣的,若是一個實體的主鍵不是0,那麼將它的狀態被標記爲Modified,一個栗子:學習
// 雖然是新建的,可是由於Id不是0,因此EF認爲是已存在的 var student = new Student(){ StudentId = 1, StudentName = "Steve" }; using (var context = new SchoolDBEntities()) { context.Entry(student).State = student.StudentId == 0? EntityState.Added : EntityState.Modified; context.SaveChanges(); }
在數據庫中執行以下代碼,注意:若是數據庫中沒有StudentId 爲1的記錄時,會報異常spa
exec sp_executesql N'UPDATE [dbo].[Student] SET [StudentName] = @0 WHERE @@ROWCOUNT > 0 AND [StudentID] = @1'N'@0 varchar(50),@1 int',@0='Steve',@1=1
上邊部分咱們學習了經過主鍵值來設置實體的狀態,這裏咱們將學習怎麼去保存一個實體圖集。設計
在離線場景中保存一個實體圖集是一件比較複雜的事,咱們須要進行認真的設計。離線場景中保存實體圖集最須要解決的問題是給實體圖集中的每個實體添加標記適當的狀態。可是怎麼去設計呢?在下圖中咱們能夠看到新的Context根本不知道每一個實體的狀態。code
咱們必須在執行SaveChange()方法前肯定每個實體的狀態,下邊介紹經過主鍵設置實體圖集狀態的方法htm
咱們能夠經過主鍵來設置實體圖集中每個實體的狀態。如前邊保存實體時介紹的,若是一個實體的主鍵是CLR數據類型的默認值(如int類型的默認值是0),那麼咱們認爲這個實體是新建的,能夠將這個實體標記爲Added,在數據庫執行Insert命令;若是主鍵值不是CLR數據類型的默認值,咱們認爲這個實體是已經存在了,標記爲Modified,在數據庫執行Update命令。
一個栗子:
var student = new Student() { //Root entity (沒有主鍵值 Standard = new Standard() //Child entity (有主鍵值) { StandardId = 1, StandardName = "Grade 1" }, Courses = new List<Course>() { new Course(){ CourseName = "Machine Language" }, //Child entity (沒有主鍵值) new Course(){ CourseId = 2 } //Child entity (有主鍵值) } }; using (var context = new SchoolDBEntities()) { //給實體圖集中的全部實體的狀態進行標記 context.Entry(student).State = student.StudentId == 0 ? EntityState.Added : EntityState.Modified; context.Entry(student.Standard).State = student.Standard.StandardId == 0 ? EntityState.Added : EntityState.Modified; foreach (var course in student.Courses) context.Entry(course).State = course.CourseId == 0 ? EntityState.Added : EntityState.Modified; context.SaveChanges(); }
在上邊的栗子中,Student實體圖集包含Standard和Course實體,context經過每一個實體的主鍵對該實體的狀態進行標記。
在離線場景刪除一個實體很簡單,只需經過Entry()方法把實體的狀態標記爲Deleted便可,注:咱們在將離線實體附加到上下文提過,當父實體的狀態是Deleted時,經過Entry()方法附加實體圖集時,實體圖集的全部子實體都爲null,因此在執行SaveChange()進行數據庫刪除時,只刪除父實體的記錄!一個簡單的栗子:
// 待刪除的實體 var student = new Student(){ StudentId = 1 }; using (var context = new SchoolDBEntities()) { context.Entry(student).State = System.Data.Entity.EntityState.Deleted; context.SaveChanges(); }
在上邊的例子中,Student實體的實例只有主鍵值,刪除一個實體也只須要主鍵值就能夠了。在數據庫中執行以下代碼:
delete [dbo].[Student] where ([StudentId] = @0)',N'@0 int',@0=1
EF系列目錄連接:Entity Franmework系列教程彙總