【Entity Framework】Entity Framework 我所不知道的事

Entity Framework 我所不知道的事

這兩天參加保哥的 Entity Framework 6 開發實戰

 

一直以來我是個,你給我任務,我就會達成任務。

 

你叫我用什麼技術,我會很快的會用這個技術。

 

但是,往往都是蜻蜓點水,會一點,然後,就在錯誤中成長。

 

也不停的期望自己逃脫這循環。

 

Entity Framework也是一樣,我會用,But,就跟上述情況一樣。

 

這次上課,讓我更瞭解這門技術,和眉角。

 

以下記錄那些我不知道的事情。

 

關於:DbEntityEntry<TEntity>

 

Entity Framework 在預設情況下,是會有所謂的變更機制 ,背後會知道EntityState 列舉類型

1

 

而透過DbEntityEntry的Class,可以幫助我們取得在變更機制中的狀態、物件內容。

 

   1: using (var db = new ContosoUniversityEntities())
   2:    {
   3:        var cour = db.Course.Find(1);
   4:        Console.WriteLine("DB中的資料:" + cour.Credits);
   5:        cour.Credits = 1000;
   6:        var courEntry = db.Entry<Course>(cour);
   7:  
   8:        if (courEntry.State == EntityState.Modified)
   9:        {
  10:            Console.WriteLine("原始資料:" + courEntry.OriginalValues.GetValue<int>("Credits"));
  11:            Console.WriteLine("目前資料:" + cour.Credits);
  12:        }
  13:    }

 

結果如下:

2

OriginalValues就是我們異動前的資料。

 

一個實用的技巧:

若Table設計為統一有UpdateDatetime的方法,也可以Override SaveChanges事件中:如下:

   1: //透過Partial Class特性
   2: public partial class ContosoUniversityEntities : DbContext
   3: {
   4:     public override int SaveChanges()
   5:     {
   6:         //取得所有存在變更狀態中的資料
   7:         var entities = this.ChangeTracker.Entries();
   8:  
   9:         foreach (var entry in entities)
  10:         {
  11:             //若型別為Course處理
  12:             if (entry.Entity is Course)
  13:             {
  14:                 //若變更機制狀態為Add-即新增
  15:                 if (entry.State == EntityState.Added)
  16:                 {
  17:                     //寫CreateOn & ModifiedOn的時間,此AP所有的Course物件透過SaveChanges 做存檔時就不必賦予該兩個屬性值。
  18:                     entry.CurrentValues.SetValues(new
  19:                     {
  20:                         ModifiedOn = DateTime.Now,
  21:                         CreatedOn = DateTime.Now
  22:                     });
  23:                 }
  24:  
  25:                 //若變更機制狀態為Modified-即Update
  26:                 if (entry.State == EntityState.Modified)
  27:                 {
  28:                     //寫ModifiedOn的時間,此AP所有的Course物件透過SaveChanges 做更新時就不必賦予該屬性值。
  29:                     entry.CurrentValues.SetValues(new
  30:                     {
  31:                         ModifiedOn = DateTime.Now
  32:                     });
  33:                 }
  34:             }
  35:         }
  36:  
  37:         return base.SaveChanges();
  38:     }
  39: }

 

透過今天一天的學習,我也搞懂之前一段一直不懂的一個行為。

 

Entity Framework 有所謂的【連線模式】與【離線模式】。

 

想像一下,在同一個DbContext連線底下做所有的事情就是連線模式。

 

注意,變更機制的所以狀態的生命週期只存在一個DbContext連下底下。

 

看一下離線模式的範例:

   1: public static void 模擬離線模式_不會更新成功()
   2: {
   3:     Course c;
   4:     using (var db = new ContosoUniversityEntities())
   5:     {
   6:         c = db.Course.Find(1);
   7:         Console.WriteLine("DB Data:" + c.Credits);
   8:  
   9:         c.Credits = 1;
  10:     }
  11:  
  12:     using (var db = new ContosoUniversityEntities())
  13:     {
  14:         Console.WriteLine("異動機制狀態:" + db.Entry(c).State);
  15:  
  16:         db.SaveChanges();
  17:  
  18:         c = db.Course.Find(1);
  19:         Console.WriteLine("DB Data 更新後:" + c.Credits);
  20:     }
  21: }

 

我模擬離線模式的方法是:透過兩個ContosoUniversityEntities的Using 區隔兩個DbContext的生命週期。

 

所以,我雖然在第一個Using取回了 Course也設定了Credits=1,但此時沒有做SaveChanges的動作。

 

是在第二個Using中做SaveChanges的動作。結果就是,第二個Using根本沒有變更機制的任何資訊,所以,沒有任何Update的動作成立。

 

結果如:

3

 

但,透過一個方式,我們可以將變更機制中的訊息,在第二個Using區段,恢復。如下:

   1: public static void 模擬離線模式_更新成功()
   2: {
   3:     Course c;
   4:     using (var db = new ContosoUniversityEntities())
   5:     {
   6:         c = db.Course.Find(1);
   7:         Console.WriteLine("DB Data:" + c.Credits);
   8:  
   9:         c.Credits = 100;
  10:     }
  11:  
  12:     using (var db = new ContosoUniversityEntities())
  13:     {
  14:         Console.WriteLine("異動機制狀態:" + db.Entry(c).State);
  15:  
  16:         //將c這個Course的型別,附加上去,同時改變異動機制中的狀態
  17:         db.Entry(c).State = System.Data.Entity.EntityState.Modified;
  18:  
  19:         Console.WriteLine("異動機制狀態:" + db.Entry(c).State);
  20:  
  21:         // db.Entry(c).State的狀態為Modified,所以更新成立。
  22:         db.SaveChanges();
  23:  
  24:         c = db.Course.Find(1);
  25:         Console.WriteLine("DB Data 更新後:" + c.Credits);
  26:     }
  27: }

 

主要異動第二個Using區段,將異動機制的資訊附加上去。

結果:

4

 

還記得之前看一篇Entity Framework 更新時出現「ObjectStateManager 中已經有具有相同索引鍵的物件。ObjectStateManager 無法追蹤多個具有相同索引鍵的物件。」錯誤,基

本上都看不太懂,但,知道怎麼用。

上完課,我都秒懂拉!!!

 

未來,11、12月會瘋狂上課。應該可以讓我的底打的更好。加油了!!

 

明天要正式邁入而立之年的老人家!!!老淚開始在眼珠轉阿轉!!