這幾天在上MVC的課程,有一個同學問到一個很不錯的問題,這個問題大致上是這樣的.
為什麼ASP.NET MVC的範例,修改資料的時候,不需要Attach??
程式碼在下面
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include = "Id,FirstName,LastName")] Emp emp) { if (ModelState.IsValid) { db.Entry(emp).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(emp); }
其實這個問題,很久以前有研究過,但後來並沒有寫到Blog上,所以也忘記了…而基本上,上面的程式碼,是從ASP.NET MVC範本出來的,大家可以看到,只要Emp這個物件傳進來之後,並且把Emp塞到db.Entty()裡面,在改State成Modified後,就可以了。完全不用Attach!!
但是不用Attach,DBContext怎麼會知道我們要更新甚麼東西呢??
其實我們去看MSDN的文件,官方也這樣寫的;如果你有一個Entity,並且你已經知道它存在於資料庫,但這個Entity裡面的東西已經被改變,那你可以告訴DBContext要Attach,並且將狀態設為Modified!!,如下程式碼。
var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; using (var context = new BloggingContext()) { context.Entry(existingBlog).State = EntityState.Modified; // Do some more work... context.SaveChanges(); }
等等,我們還是沒看到Attach阿!!?…
理論上應該如這篇文章的內容一樣,是這樣這寫吧??..我們應該先Attach這個物件,然後再把State改為Modified…那為什麼上面的範例不用??
db.Users.Attach(updatedUser); db.Entry(updatedUser).State = EntityState.Modified; db.SaveChanges();
其實原因很簡單,那是因為背後他幫我們自動Attach了,所以我們就可以不用Attach了…
那是在db.Entry()這個方法裡面進行Attach的嗎??…
錯…我們可以看到下圖;當我們執行完db.Entry()後,根本就還沒開始追蹤,甚至現有物件和原始物件都還是沒東西的狀況…
那到底在哪邊?
答案就在這一行,真正會自動幫忙Attach的地點其實是在設定State的這個地方…
dbEntry.State = EntityState.Modified;
其實我們反組譯看看,就可以看到如下圖。
是的,其實在我們設定State的時候,會用到set,所以真正的自動執行Attach的地方,就是這裡… ( 老實說,真的意想不到阿= =|| )
也因此,我們也不用多寫Attach,只要變更State的時候,他就會自動幫我們Attach去上,並開始追蹤了~~
參考資料