2014年3月13日 星期四

ASP.NET MVC 4 WebApi Put 時資料無法更新之問題

今天我在做資料更新時,將資料傳送到 API Put 內,再將資料更新,如以下程式碼:
public HttpResponseMessage Put(Employee employee)
{
    if (ModelState.IsValid)
    {
        employee.Company = db.Company.Find(employee.Company.CompanyId);
        
        // ... 更多的關聯表

        db.Entry(employee).State = EntityState.Modified;       

        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
        }
    }
    else
    {
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
    }

    return Request.CreateResponse(HttpStatusCode.OK);
}

因為在頁面上是使用 Extjs,所以在資料傳送過來時,關聯的資料只會有 Key 值,必需再去與資料庫要被關聯的完整資料,要不然資料將會被自動新增,會多了筆垃圾資料,多做幾次就會有幾筆,所以必須得在與資料庫要一次。

此時問題來了,在我將頁面上資料送到 Put 時,發現 Employee 中的資料可以被更新,但是 Employee 關聯的表的 ID 沒有被更新。

什麼???!! 這是什麼情況。

參考了許多資料:EntityState 列舉型別ObjectStateEntry 類別EDM的一些常见处理数据操作MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化Entity Framework 4.1 Code First学习之路(二)EntityFrameworkAdd方法与Attach区别

後來我觀察了一下,在 Put 一進來時 db.Entry(employee).State 為 Detached ( 意思是不在 Context 裡,沒有被追蹤 ),接著我將程式碼改為:
// 將狀態改為 Unchanged,也就是將它附加到 Context 內
db.Employee.Attach(employee); 
// 將狀態改為 Modified
db.Entry(employee).State = EntityState.Modified;

結果還是一樣.....這我就看不懂了,找了許多範例都是這樣,都沒有看到資料在 Put 進來之後,還有做修改的。但後來看到一篇文章 Working With Entity Framework Detached Objects
先搜尋出該筆資料塞進另一個實體,再將此實體加入關聯的表的資料,接著使用 Entry().CurrentValues.SetValues() 將修改過的資料塞到實體,最後在更新。

程式碼如下:
public HttpResponseMessage Put(Employee employee)
{
    if (ModelState.IsValid)
    {
        Employee _employee = db.Employee.Find(employee.EmployeeId, employee.EffectiveDate);

        _employee.Company = db.Company.Find(employee.Company.CompanyId);

        // ... 更多關聯表        

        db.Entry(_employee).CurrentValues.SetValues(employee);

        try
        {
            db.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
        }
    }
    else
    {
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
    }

    return Request.CreateResponse(HttpStatusCode.OK);
}

程式碼改為這樣就可以更新了,重新建立一個實體去找出資料庫最新的資料 ( 狀態為 Unchanged ),再將所有修改過的值原封不動的設定到實體上 ( 狀態為 Modified ),最後在送到資料庫去更新,這樣就解決問題了。

沒有留言 :

張貼留言

Related Posts Plugin for WordPress, Blogger...