本節,我們將介紹一些改善EF代碼的相關方法,如NoTracking,GetObjectByKey, Include等。
l MergeOption.NoTracking
當我們只需要讀取某些資料而不需要刪除、更新的時候,可以指定使用MergeOption.NoTracking的方式來執行唯讀查詢(EF預設的方式是AppendOnly)。當指定使用NoTracking來進行唯讀查詢時,與實體相關的引用實體不會被返回,它們會被自動化佈建為null。因此,使用NoTracking可以提升查詢的效能。範例程式碼如下:
[Test]
public void NoTrackingTest()
{
using (var db = new NorthwindEntities1())
{
//針對Customers查詢將使用MergeOption.NoTracking
db.Customers.MergeOption = MergeOption.NoTracking;
var cust = db.Customers.Where(c => c.City == "London");
foreach (var c in cust)
Console.WriteLine(c.CustomerID);
//也可以這樣寫
//var cust1 = ((ObjectQuery<Customers>)cust).Execute(MergeOption.NoTracking);
//Esql寫法
//string esql = "select value c from customers as c where c.CustomerID='ALFKI'";
//db.CreateQuery<Customers>(esql).Execute(MergeOption.NoTracking).FirstOrDefault();
}
}
l GetObjectByKey/First
GetObjectByKey:
在EF中,使用GetObjectByKey方法擷取資料時,它首先會查詢是否有緩衝,如果有緩衝則從緩衝中返回需要的實體。如果沒有則查詢資料庫,返回需要的實體,並添加在緩衝中以便下次使用。
First: 總從資料庫中提取需要的實體。
因此,我們應在合適的地方選擇GetObjectByKey方法來擷取資料,以減少對資料庫的訪問提升效能。範例程式碼如下:
[Test]
public void GetByKeyTest()
{
using (var db = new NorthwindEntities1())
{
//從資料庫中提取資料
var cst = db.Customers.First(c => c.CustomerID == "ALFKI");
Console.WriteLine(cst.CustomerID);
//將從緩衝中提取資料
EntityKey key = new EntityKey("NorthwindEntities1.Customers", "CustomerID", "ALFKI");
var cst1 = db.GetObjectByKey(key) as Customers;
Console.WriteLine(cst1.CustomerID);
}
}
此外,需要注意的是如果GetObjectByKey沒有擷取到合格資料,那麼它會拋異常。為了避免此情況發生,在有可能出現異常的地方,我們應該使用TryGetObjectByKey方法。TryGetObjectByKey方法擷取資料的方式和GetObjectByKey類似,只是當沒有取到合格資料時,TryGetObjectByKey會返回null而不是拋異常。範例程式碼如下:
[Test]
public void TryGetByKeyTest()
{
using (var db = new NorthwindEntities1())
{
//沒有合格資料會有異常拋出
EntityKey key = new EntityKey("NorthwindEntities1.Customers", "CustomerID", "♂風車車.Net");
var cst = db.GetObjectByKey(key) as Customers;
Console.WriteLine(cst.CustomerID);
//沒有合格資料會有返回null
EntityKey key1 = new EntityKey("NorthwindEntities1.Customers", "CustomerID", "♂風車車.Net");
Object cst1 = null;
db.TryGetObjectByKey(key1, out cst1);
if (cst1 != null)
Console.WriteLine(((Customers)cst1).CustomerID);
}
}
l First /FirstOrDefault
First: 當我們使用First來擷取資料,如果沒有合格資料,那麼我們的代碼將會拋出異常。
FirstOrDefault: 當我們使用FirstOrDefault來擷取的資料,如果沒有合格資料,那麼它將返回null。
顯然,對於一個良好的代碼,是對可以預見的異常進行處理,而不是等它自己拋出來。範例程式碼如下:
[Test]
public void FirstTest()
{
using (var db = new NorthwindEntities1())
{
//拋異常的代碼
var cst = db.Customers.First(c => c.CustomerID == "♂風車車.Net");
Console.WriteLine(cst.CustomerID);//此處將出拋異常
//推薦的使用如下代碼:
var cst1 = db.Customers.FirstOrDefault(c => c.CustomerID == "♂風車車.Net");
if (cst1 != null)
Console.WriteLine(cst1.CustomerID);
}
}
l 消極式載入/Include
EF不支援實體的部分屬性消極式載入,但它支援實體關聯的消極式載入。預設情況,實體的關係是不會載入。如下代碼:
[Test]
public void IncludeTest()
{
using (var db = new NorthwindEntities1())
{
var csts = db.Customers;
foreach (var c in csts)
{
Console.WriteLine(c.CustomerID);
foreach (var o in c.Orders)
Console.WriteLine(" " + o.OrderID);
}
}
}
上述代碼中,因為Orders沒有被載入,所以在輸出Orders的時候,是不會有任何輸出的。
當我們需要載入某些關聯的關係時,可是用Include方法,如下代碼所示:
[Test]
public void IncludeTest()
{
using (var db = new NorthwindEntities1())
{
var csts = db.Customers.Include("Orders");
foreach (var c in csts)
{
Console.WriteLine(c.CustomerID);
foreach (var o in c.Orders)
Console.WriteLine(" " + o.OrderID);
}
}
}
上述代碼中,Customers關聯的Orders將被載入。