Entity Framework 6 新功能 Logging/Store Procedure
摘要
在Entity Framework6中有兩個新的功能,DB Loggin和Stored Procedure的映射
Entity Framework 6已經從Beta版本來到了RC1版本,我們可以看到升級之後EF6有兩個亮眼的新功能,DB Logging和CRUD的Stored Procedure映射。
EF6從Beta到RC1添加了什麼
在Visual Studio2013中要將原本專案採用的EF6 Beta升級到RC1是一件很簡單事,只需要在套件管理主控台輸入: update-package EntityFramework -pre
前置作業
首先建立一個測試用的模型:TestModel。
圖1. TestModel
接下來撰寫這個TestModels檔案的內容:
public class TestModel
{
[ Key]
public int TestId { get; set; }
public string TestName { get; set; }
}
public class TestContext : DbContext
{
public DbSet< TestModel> TestModels { get; set; }
public TestContext()
: base( "DefaultConnection" )
{ }
protected override void OnModelCreating( DbModelBuilder mb)
{
mb.HasDefaultSchema( "Test" );
base.OnModelCreating(mb);
}
}
為了讓整個Entity Framework啟動起來,我們到HomeController中寫一些無意義的程式碼:
public ActionResult Index()
{
using ( TestContext ctx = new TestContext())
{
ctx.TestModels.ToList();
}
return View();
}
按下F5執行整個專案後,由於是第一次載入且啟動Entity Framework機制,故會等比較久。當首頁開啟來後檢查一下資料庫是否已建立TestModel這張資料表。
圖2. SQL Server物件總管的畫面
前置作業完成之後,接下來就把Entity Framework 6 RC1的兩項新功能一一啟用。
EF Code First - Stored Procedure映射
資料庫產品有著許多與OR/M映射不匹配的狀況,EF 6因此引入一個新的功能到Code First中,讓開發人員能夠更容易的操作資料庫。欲在TestModel中啟用Stored Procedure,只需在其Context的OnModelCreating方法中添加如下程式碼:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.HasDefaultSchema( "Test");
mb.Entity< TestModel>()
.MapToStoredProcedures();
base.OnModelCreating(mb);
}
MapToStoreProcedures()方法具有兩個多載,其一為無參數,使用預設Code First的StoreProcedure建構方法來建立Stored Procedure;另一個則有一個Action型別的輸入參數,讓開發人員可以客製化目前現存的Stored Procedure其:名稱,參數...等等。
如果在這個時候直接執行會發生錯誤,這是因為我已經修改了Code First中的Context程式,並且因此與資料庫中現行的內容出現了差異,故需要在套件管理器中執行以下命令:
Enable-Migrations -ContextTypeName EF6Test.Models.TestContext
待執行完畢後,可以發現到專案的檔案結構已經出現了一個名為Migrations的資料夾:
若單單只有啟動Entity Framework的移轉功能但卻沒有實際將我們本次修改的內容進行明確的宣告,則此次的修改仍不會被紀錄起來;而每次修改Code First的POCO或是Context類別後都需要進行結構異動的移轉宣告。本次異動移轉宣告指令如下:
Add-Migration TestStoredProcedure
執行完命令後會在專案中新增一個[日期時間]_TestStoredProcedure的類別檔,打開後可以看到其產生的StoredProcedure。
public partial class TestStoredProcedure : DbMigration
{
public override void Up()
{
CreateStoredProcedure(
"Test.TestModel_Insert" ,
p => new
{
TestName = p.String(),
},
body:
@"INSERT [Test].[TestModels]([TestName])
VALUES (@TestName)
DECLARE @TestId int
SELECT @TestId = [TestId]
FROM [Test].[TestModels]
WHERE @@ROWCOUNT > 0 AND [TestId] = scope_identity()
SELECT t0.[TestId]
FROM [Test].[TestModels] AS t0
WHERE @@ROWCOUNT > 0 AND t0.[TestId] = @TestId"
);
CreateStoredProcedure(
"Test.TestModel_Update" ,
p => new
{
TestId = p.Int(),
TestName = p.String(),
},
body:
@"UPDATE [Test].[TestModels]
SET [TestName] = @TestName
WHERE ([TestId] = @TestId)"
);
CreateStoredProcedure(
"Test.TestModel_Delete" ,
p => new
{
TestId = p.Int(),
},
body:
@"DELETE [Test].[TestModels]
WHERE ([TestId] = @TestId)"
);
}
public override void Down()
{
DropStoredProcedure( "Test.TestModel_Delete" );
DropStoredProcedure( "Test.TestModel_Update" );
DropStoredProcedure( "Test.TestModel_Insert" );
}
}
從上述程式碼可以看到DBMigration類別已經自動產出了Stored Procedure內容: Insert/Update/Delete。但卻沒有Select ??
接下要將Stored Procedure在資料庫中建立,故,一樣在套件管理控制台輸入: update-database
圖3. 更新資料庫
使用DB Logging來監控EF的活動
DB Logging將EF與資料庫之間的互動都紀錄下來。早前有兩個非常棒的ASP.Net套件:MiniProfiler以及Glimpse;它們讓我們可以看到EF的SQL陳述句,如今,EF也提供了這項功能。DB Logging主要目標是提供:
1. 瞭解EF的Linq是怎麼轉譯成SQL陳述句
2. 深入探索那些可能會造成執行時間過長的查詢
3. 找出EF沒有正確回傳結果的原因
啟動偵錯很簡單,僅需指派一個帶字串輸入參數的Action物件即可。
public ActionResult Index()
{
using (TestContext ctx = new TestContext()) {
ctx.Database.Log = (log) => { Debug .WriteLine(log); };
ctx.TestModels.ToList();
}
return View();
}
現在,當我們執行應用程式並且瀏覽到首頁面。
假若我們打開偵錯主控台視窗,我們會看到"Select ..."這個SQL陳述句共花費12ms於整個執行,而其回傳結果為SqlDataReader。
圖4. DB Logger所紀錄的項目
整齊乾淨,假若我們想要客製化紀錄的字串呢?EF提供了許多擴充點可以讓我們做出像是Glimpse的紀錄和追蹤功能。