2013年11月18日 星期一

DbContext簡化ObjectContext三項需要複雜的操作

   ObjectContext類別是.Net Framework 4 Entity Framework核心API之一;並且也是一個可以讓操作查詢/變異追蹤/更新資料庫。DbContext類別將ObjectContext包裝起來,並且提供好用的功能,並且還提供原本在ObjectContext需要複雜的操作包裝成更簡單的方法。
   DbContext轉成ObjectContext的方法:
ObjectContext objCtx = (myDbContext as IObjectContextAdapter).ObjectContext;

Entity Framework團隊建議除非必要,否則盡可能不要直接使用ObjectContext來進行操作。接下來討論DbContext簡化ObjectContext三項需要複雜的操作。


1. DbSet.Find

      在ObjectContext中若要依資料表主鍵取得某筆資料,則需要使用如下Linq to Entity語法:
var result = from e in objCtx.Employee where e.Id == 3 select e;
Employee emp = result.SingleOrDefault();
或是寫成:
Employee emp = objCtx.Employee.SignleOrDefault(e => e.Id == 3);
但在DbContext,只需要利用DbSet提供的Find方法即可:
Employee emp = dbCtx.Employee.Find(3);

DbSet.Find為了效能它並不會每次查詢時都去資料庫撈資料;它會先從Context目前有追蹤的實體中去查是否有那一個實體其Id是符合的,若符合則直接回傳。

   DbSet.Find方法的輸入參數是一個參數陣列,故,當需要查詢的實體其採用的是複合主鍵時就可以利用參數陣列的方式將主鍵查詢值投入。
Employee emp = dbCtx.Employee.Find(3,"John");

2. 取得Context已追蹤的POCO

      ObjectContext要追蹤自己已追蹤過的實體相當的不方便,必須要從ObjectstateEntries下手:
objCtx.ObjectStateManager
      .GetObjectStateEntries(EntityState.Added |
                             EntityState.Modified |
                             EntityState.Unchanged)
      .Where(e => e.Entity is Employee)
      .Count();

   而DbContext僅需呼叫DbSet的Local方法即可取得所有已被追蹤的POCO:
IEnumerable<Employee> ieEmp = dbCtx.Employee.Local;

   兩者在回傳的資料有個很大的不同之處在於GetObjectStateEntries其回傳的是不論任何實體實體都會回傳,但是DbSet.Local僅會回傳開發人員所指定的的追蹤資料。都會回傳,但是DbSet.Local僅會回傳開發人員所指定實體的追蹤資料。

3. 不追蹤式查詢

      若使用Entity Framework時僅需要查詢而不需要做其它事情時,盡可能採用不追蹤式查詢,因為這對於效能來說有很大的提升。
   一般處理ObjectContext的不追蹤式查詢會利用以下方式:
string strESql = " Select e, e.Name " +
                 " From objCtx.Employee As e " +
                 " Where e.Id = 3 ";
var query = objCtx.CreateQuery<DbDataRecord>(strESql);
query.MergeOption = System.Data.Objects.MergeOption.NoTracking;
var employee = query.SingleOrDefault();
   DbContext為了讓這個動作變得更加簡便,針對IQueryable添加了一個AsNoTracking的擴充方法:
dbCtx.Employee
     .Where(e => e.Id == 3)
      .AsNoTracking();
   ObjectContext在追蹤實體時會使用ObjectStateEntry去紀錄;而DbContext則是採用DbEntityEntry去紀錄。

1 則留言: