2016年5月21日 星期六

[Entity Framework 6] Attach and Detach

.NET   Entity Framework    ORM


雖說自己在先前的文章:
曾提到用不同的DbContext來操作Entity的小陷阱。

結果一年後的今天還是踩到了這個雷 ~_~|| (而且完全沒有Exception message …)


Reproduce the problem

在以下程式碼中,當Entity需要傳到不同的方法操作時,如果是不同的DbContext,會造成實際上已更新物件,但資料庫卻未更新的情況。

//In Method 1
using (var daoService = new BloodTypeService<BloodType>(new TmsDbContext()))
{
    bloodType = daoService.GetAll().ToList().ElementAt(0);
    LogUtility.Logger.Debug(bloodType.Name);
}

//In Method 2
using (var daoService = new BloodTypeService<BloodType>(new TmsDbContext()))
{
    bloodType.Name = "AAA";
    daoService.Update(bloodType); //包含SaveChanges()

    var bloodTypeReQuery = daoService.GetAll().ToList().ElementAt(0);
    LogUtility.Logger.Debug(bloodTypeReQuery.Name);
}

上面的執行結果是 
A
A

也就是沒有更新到實體資料庫

Refinement 1


var dbContext = new TmsDbContext();

//In Method 1
using (var daoService = new BloodTypeService<BloodType>(dbContext))
{
      bloodType = daoService.GetAll().ToList().ElementAt(0);
      LogUtility.Logger.Debug(bloodType.Name);
}

//In Method 2
using (var daoService = new BloodTypeService<BloodType>(dbContext))
{
      bloodType.Name = "AAA";
      daoService.Update(bloodType); //包含SaveChanges()

      var bloodTypeReQuery = daoService.GetAll().ToList().ElementAt(0);
      LogUtility.Logger.Debug(bloodTypeReQuery.Name);
}

上面的兩個方法共用同一個DbContext後,就可以成功更新該筆資料庫的資料。

Output結果為
A
AAA

Refinement 2

也可以使用Detach & attach的方式來修正程式碼。

BloodType bloodType = null;

//In Method 1
var dbContext1 = new TmsDbContext();
using (var daoService = new BloodTypeService<BloodType>(dbContext1))
{
                bloodType = daoService.GetAll().ToList().ElementAt(0);

                //Detach method 1 : Using ObjectContext
                ObjectContext objContext1 = ((IObjectContextAdapter)dbContext1).ObjectContext;
                objContext1.Detach(bloodType);
                //Detach method 2 : Using EntityState to detach
                //dbContext1.Entry(bloodType).State = EntityState.Detached;

                LogUtility.Logger.Debug(bloodType.Name);
}

//In Method 2
var dbContext2 = new TmsDbContext();
using (var daoService = new BloodTypeService<BloodType>(dbContext2))
{
                //Attach method 1 : Using DbSet.Attach()
                dbContext2.Set(typeof(BloodType)).Attach(bloodType);
                //Attach method 2 : Using EntityState to attach (If the DAO is modified before attaching it, must use this way)
                //dbContext2.Entry(bloodType).State = EntityState.Modified;

                bloodType.Name = "AAA";
                daoService.Update(bloodType); //包含SaveChanges()

                var bloodTypeReQuery = daoService.GetAll().ToList().ElementAt(0);
                LogUtility.Logger.Debug(bloodTypeReQuery.Name);
}



沒有留言:

張貼留言