Entity Framework - 為什麼修改的資料不用Attach

21 August 2014 — Written by Sky Chang
#ASP.NET MVC#Entity Framework

這幾天在上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()後,根本就還沒開始追蹤,甚至現有物件和原始物件都還是沒東西的狀況…

image

那到底在哪邊?

答案就在這一行,真正會自動幫忙Attach的地點其實是在設定State的這個地方…

dbEntry.State = EntityState.Modified;

其實我們反組譯看看,就可以看到如下圖。

image

是的,其實在我們設定State的時候,會用到set,所以真正的自動執行Attach的地方,就是這裡… ( 老實說,真的意想不到阿= =|| )

也因此,我們也不用多寫Attach,只要變更State的時候,他就會自動幫我們Attach去上,並開始追蹤了~~

參考資料

Sky & Study4.TW