Entity Framework 4.1/4.3 之六 (DBContext 之 3 狀態跟蹤)
咱們接着來講DBContext,這回內容將與DBContext 2中所講的內容連貫起來。
二、DBContext對於實體的增、刪、改 (Adding, Changing, and Deleting Entities)
DBContext 2中我們講到了“增、刪、改”,其中已經講了“增、刪、改”。還有部分內容沒講,我們補全。
(1)、查找增加模式 (The “Find or Add” Pattern)
場景:我們常常會增加一條記錄,增加的步驟是先查找有沒有相同記錄存在,如果不存在內里將新記錄新增到數據庫中。在老版EF中我們會執行兩次操作:即先找,在增。這無形中要與數據庫交互兩。
DBContext為我們提供了新的解決方案,即Find or Add,我們來看看代碼:
private static void FindOrAddPerson() { using (var context = new BreakAwayContext()) { var ssn = 123456789; var person = context.People.Find(ssn)?? context.People.Add(new Person { SocialSecurityNumber = ssn, FirstName = "jerry", LastName = "tom" }); Console.WriteLine(person.FirstName); } }
代碼看起來非常的直觀,如果Find(ssn)在緩存或者數據庫中找到了該記錄,則輸出,否則則新增一條記錄。
(2)、新增關系數據(Adding a Relationship Between Objects)
說實話,這個理解起來有點繞,不好解釋。我們還是直接來看下面的代碼吧!
private static void NewGrandCanyonResort() { using (var context = new BreakAwayContext()) { var resort = new Resort { Name = "Pete's Luxury Resort" }; context.Lodgings.Add(resort); var canyon = (from d in context.Destinations where d.Name == "Grand Canyon"
select d).Single(); canyon.Lodgings.Add(resort); context.SaveChanges(); } }
Destinations 與 Lodgings 是一對多的關系,首先我們創建一個 resort 對象,將它加入到 Lodgings 集合中。然后我們找到父集合Destinations ,將resort 對象加入到Destinations包含的Lodgings集合中,然后SaveChanges,這種關聯關系就建立起來了,相應的數據也保存到了數據庫中。就是這么個意思,通俗的講,就是先在從表里增加一條記錄,然后將新增的記錄與主表關系起來。你明白了嗎?
這里我要強調一點,兩表關聯,對應該的關系ID要統一。比如主表中的主鍵是 classId ,那么相關系的從表關聯id 也應該是classId,如果不統一的話,EF很難自動進行Map,除非人為的在Map文件中重改映射關系。
(3)、修改關系數據 (Changing a Relationship Between Objects)
private static void ChangeLodgingDestination() { using (var context = new BreakAwayContext()) { var hotel = (from l in context.Lodgings where l.Name == "Grand Hotel"
select l).Single(); var reef = (from d in context.Destinations where d.Name == "Great Barrier Reef"
select d).Single(); hotel.Destination = reef; context.SaveChanges(); } }
這是生成Sql語句:
exec sp_executesql N'update [dbo].[Lodgings]
set [destination_id] = @0
where ([LodgingId] = @1)
',N'@0 int,@1 int',@0=4,@1=1
這里Lodgings依然扮演着從表的角色,代碼暫示了主從表關系的變更。當然,這只是DBContext中給我們提供的一個解決方案。我個人習慣直接修改關聯關系ID的值。
(4)、刪除關系(Removing a Relationship Between Objects)
private static void RemovePrimaryContact() { using (var context = new BreakAwayContext()) { var davesDump = (from l in context.Lodgings where l.Name == "Dave's Dump"
select l).Single(); context.Entry(davesDump).Reference(l => l.PrimaryContact).Load(); davesDump.PrimaryContact = null; context.SaveChanges();
} }
private static void RemovePrimaryContact() { using (var context = new BreakAwayContext()) { var davesDump = (from l in context.Lodgings where l.Name == "Dave's Dump"
select l).Single(); davesDump.PrimaryContactId = null; context.SaveChanges(); } }
刪除關系沒什么好講的,一種方式是關聯子集置空,一種方式是將關聯id置空。
(5)、簡單描述一下跟蹤狀態,這里只是簡單的了解,后續會有專門的詳解。(Working with Change Tracking)
狀態清單:• DbSet.Add
• DbSet.Find
• DbSet.Remove
• DbSet.Local
• DbContext.SaveChanges
• Running any LINQ query against a DbSet
• DbSet.Attach
• DbContext.GetValidationErrors
• DbContext.Entry
• DbChangeTracker.Entries
正是有了這些跟蹤狀態(Tracking),SaveChanges才知道它應該干些什么。
DetectChanges:變化檢測(Controlling When DetectChanges Is Called) 控制程序將在 變化檢測時被觸發。
大多數情況下(或者說大多說時間),在SaveChanges期間 Entity Framework 都需要知道 Tracking Change(即跟蹤狀態的改變情況)。 這里有個不太好理解的定義:Automatic DetectChanges 下面是一段應用代碼,因為目前我對Automatic DetectChanges還不太准確。所以只把代碼展示出來,大家分析分析。
private static void ManualDetectChanges() { using (var context = new BreakAwayContext()) { context.Configuration.AutoDetectChangesEnabled = false; var reef = (from d in context.Destinations where d.Name == "Great Barrier Reef"
select d).Single(); reef.Description = "The world's largest reef."; Console.WriteLine( "Before DetectChanges: {0}", context.Entry(reef).State); context.ChangeTracker.DetectChanges(); Using Snapshot Change Tracking | 61 Console.WriteLine( "After DetectChanges: {0}", context.Entry(reef).State); } }
private static void AddMultipleDestinations() { using (var context = new BreakAwayContext()) { context.Configuration.AutoDetectChangesEnabled = false; context.Destinations.Add(new Destination { Name = "Paris", Country = "France" });
context.Destinations.Add(new Destination { Name = "Grindelwald", Country = "Switzerland" }); context.Destinations.Add(new Destination { Name = "Crete", Country = "Greece" }); context.SaveChanges(); } }
我總覺得這個很難理解。
(6)、使用detectchanges觸發關系 (Using DetectChanges to Trigger Relationship Fix-up) (這個也是我目前不太理解的,下面是實例中的代碼)
private static void DetectRelationshipChanges() { using (var context = new BreakAwayContext()) { var hawaii = (from d in context.Destinations where d.Name == "Hawaii"
select d).Single(); var davesDump = (from l in context.Lodgings where l.Name == "Dave's Dump"
select l).Single(); context.Entry(davesDump) .Reference(l => l.Destination) .Load(); hawaii.Lodgings.Add(davesDump); Console.WriteLine( "Before DetectChanges: {0}", davesDump.Destination.Name); context.ChangeTracker.DetectChanges(); Console.WriteLine( "After DetectChanges: {0}", davesDump.Destination.Name); } }
希望代碼能讓我們明白其中的道理。
(7)、啟用和使用更改跟蹤代理 (Enabling and Working with Change Tracking Proxies)
(8)、確保新實例獲取代理 (Ensuring the New Instances Get Proxies)
(9)、創建派生類型的代理實例(Creating Proxy Instances for Derived Types)
(10)、不更改跟蹤獲取實體 (Fetching Entities Without Change Tracking)
小述:6、7、8、9、10 這幾種方式我沒有用到,也不知道他們有什么好處和優點。如果大家了解的話,請告訴我。我先將自己用過和理解的寫錯來。對於一些未知的領域,也希望大家不吝指教。好了,就寫到這里,我是百靈。
百靈注:本文版權由百靈和博客園共同所有,轉載請注明出處。
助人等於自助! mbailing@163.com