1、DbContext(上下文類)
在DbFirst模式中,我們添加一個EDM(Entity Data Model)后會自動生成一個.edmx文件,這個文件中包含一個繼承DbContext類的上下文實例,DbContext是實體類和數據庫之間的橋梁,DbContext主要負責與數據交互,主要作用:
1、DbContext包含所有的實體映射到數據庫表的實體集(DbSet < TEntity >)。
2、DbContext 將LINQ-to-Entities查詢轉換為SQL查詢並將其發送到數據庫。
3、更改跟蹤: 它跟蹤每個實體從數據庫中查詢出來后發生的修改變化。
4、持久化數據: 它也基於實體狀態執行插入、更新和刪除操作到數據庫中。
從上圖可以看出:在EF工作過程中,對實體的操作會導致實體狀態的變化,Context根據實體狀態的變化生成和執行對應的SQL語句。簡言之,對實體的操作給實體添加標簽(如Added,Deleted,Modified),DbContext根據實體的標簽生成(Insert,Delete,Update)Sql語句,然后EF通過Ado.Net執行Sql實現持久化。
2、DbContext中的DbSet
DbSet 表示上下文中給定類型的所有實體的集合或可從數據庫中查詢的給定類型的所有實體的集合。 可以使用 DbContext.Set 方法從 DbContext 中創建 DbSet 對象,DbSet對應着數據庫中的表,DbSet常用的方法如下
Add(Entity)/AddRange | 返回添加的Entity | 添加實體到context中,並給實體標記Added狀態 dbcontext.Students.Add(studentEntity) |
AsNoTracking<Entity> | DBQuery<Entity> | 獲取一個不被context緩沖和追蹤的序列,多用於獲取只讀序列 var studentList = dbcontext.Students.AsNoTracking<Student>().ToList<Student>(); |
Attach(Entity) | 返回添加的Entity | 將實體添加到context上下文中 dbcontext.Students.Attach(studentEntity); |
Find(int) | 返回對應Id的Entity | 通過主鍵獲取實體對象,如果在數據庫和context中不存在那么返回null,注:也會返回在context中存在但還沒有寫入數據庫的實體對象。 Student studEntity = dbcontext.Students.Find(1); |
Include | DBQuery | include必須是外鍵連接,且立即執行;join連接不需要外鍵 ,延時執行 var studentList = dbcontext.Students.Include("StudentAddress").ToList<Student>(); var studentList = dbcontext.Students.Include(s => s.StudentAddress).ToList<Student>(); |
Remove/RemoveRange | 返回刪除的entity | 刪除實例,並給實例對象添加deleted標記。 dbcontext.Students.Remove(studentEntity); |
SqlQuery | DBSqlQuery | 通過sql獲取實例集合. 默認情況下,返回的集合被追蹤的,可以使用AsNoTracking()取消追蹤。 var studentEntity = dbcontext.Students.SqlQuery("select * from student where studentid = 1").FirstOrDefault<Student>(); |
3.DbContext中的DBEntityEntry
在EF中實體的五種狀態:
1、detached:實體不在上下文的追蹤范圍內。如剛new的實例處於detached,可以通過Attach()添加到上下文,此時的狀態是unchanged。
2、unchanged:未改變,如剛從數據庫讀出來的實例
3、added:添加狀態 一般執行 db.Set<T>.Add(t)/ AddRange(ts)時標記為added。因為新對象在數據庫中沒有相應的記錄,所有不能轉成deleted和modified狀態。
4、deleted:刪除狀態 一般執行 db.Set<T>.Remove(t)/ RemoveRange(ts)時標記為deleted。數據庫中必須先有了相應的記錄,所有deleted不能轉為added狀態。
5、modified:修改狀態 改變了實體的屬性處於這個狀態,可以轉為deleted,不能轉為added狀態。
當EF從數據庫中提取一條記錄生成一個實體對象之后,應用程序可以針對它的操作太多了,EF是怎么知道哪個對象處於哪個狀態的?
EF的解決方案是:為當前所有需要跟蹤的實體對象,創建一個相應的DbEntityEntry對象,此對象包容着實體對象每個屬性的三個值:Current Value、Original Value和Database Value,只要比較這三個值,很容易地就知道哪個屬性值被修改了(設置:context.Configuration.AutoDetectChangesEnabled = false則不會去追蹤,默認是打開的),從而生成相應的Sql命令。對象的狀態會隨着操作而改變,我們也可以自己指定狀態:
1 //為user生成一個DbEntityEntry對象 2 DbEntityEntry userEntry = context.Entry(user); 3 userEntry.State = EntityState.Added;//添加標記 4 userEntry.State = EntityState.Deleted;//刪除標記 5 userEntry.State = EntityState.Modified;//修改標記 6 userEntry.State = EntityState.Unchanged;//無變化標記 7 userEntry.State = EntityState.Detached;//不追蹤標記
狀態間的轉化如下圖:
當DbContext執行SaveChanges()方法時,根據實體的狀態生成相應的Sql語句,通過Ado.net完成數據的持久化。
EF系列目錄鏈接:Entity Franmework系列教程匯總