Entity Framework 6 新功能 Logging/Store Procedure

  • 4823
  • 0

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。

image

圖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這張資料表。

image

圖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

image

圖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。

image

圖4. DB Logger所紀錄的項目

 

   整齊乾淨,假若我們想要客製化紀錄的字串呢?EF提供了許多擴充點可以讓我們做出像是Glimpse的紀錄和追蹤功能。