Entity Framework 我所不知道的事
這兩天參加保哥的 Entity Framework 6 開發實戰。
一直以來我是個,你給我任務,我就會達成任務。
你叫我用什麼技術,我會很快的會用這個技術。
但是,往往都是蜻蜓點水,會一點,然後,就在錯誤中成長。
也不停的期望自己逃脫這循環。
Entity Framework也是一樣,我會用,But,就跟上述情況一樣。
這次上課,讓我更瞭解這門技術,和眉角。
以下記錄那些我不知道的事情。
Entity Framework 在預設情況下,是會有所謂的變更機制 ,背後會知道EntityState 列舉類型 。
而透過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: }
結果如下:
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的動作成立。
結果如:
但,透過一個方式,我們可以將變更機制中的訊息,在第二個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區段,將異動機制的資訊附加上去。
結果:
還記得之前看一篇Entity Framework 更新時出現「ObjectStateManager 中已經有具有相同索引鍵的物件。ObjectStateManager 無法追蹤多個具有相同索引鍵的物件。」錯誤,基
本上都看不太懂,但,知道怎麼用。
上完課,我都秒懂拉!!!
未來,11、12月會瘋狂上課。應該可以讓我的底打的更好。加油了!!
明天要正式邁入而立之年的老人家!!!老淚開始在眼珠轉阿轉!!