The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

Entity Framework 如何呼叫 SQL 裡沒有回傳參數的預儲程序

其實早在 Entity Framework 4.0 之前就已經提供了從 ObjectContext 呼叫 預儲程序 (Stored Procedure) 的能力,不過早期的 Entity Framework V2 版本支援度不夠,以致於只要是這個預儲程序的回傳值的型別不是 實體 (Entity) 的話,就會無法直接從 ObjectContext 進行叫用,這個架構上的問題直到 V4 這個版本才正式解決,以下就是從 Entity Framework 呼叫預儲程序的方法。

首先,我們先在資料庫中定義一個沒有回傳值的預儲程序,其名稱為 ResetData

CREATE PROCEDURE dbo.ResetData
AS
	
	DBCC CHECKIDENT ( Log, RESEED, 0)

	RETURN

然後我們可以從「模型瀏覽器」從資料庫更新模型,以載入資料庫新建立的那個 ResetData 預儲程序:

加入後你會在 DatabaseModel.Store / 預儲程序 下看到你所匯入的預儲程序,移動到 DatabaseModel / EntityContainer.DatabaseEntities / 函式匯入 按下滑鼠右鍵,並選取 [加入函式匯入]:

然後設定你要再 Entity Framework 中使用的函式匯入名稱,並選取你剛剛匯入的預儲程序名稱,由於我們的預儲程序並沒有回傳值,因此回傳值的部分你必須勾選「無」。

然而當你在程式碼裡卻怎樣都無法叫用到 ResetData() 這個方法,因為這種作法在 Entity Framework V2 是不支援的!!

如上完全相同的操作步驟,如果是 Entity Framework V4 ( .NET Framework 4.0 ) 的專案,在 Visual Studio 2010 中操作就完全沒問題,純粹就是 Entity Framework V2 不支援這種用法而已。

我們從 Entity Framework 設計工具產生的 C# 原始檔來看這兩個版本中的差異:

在 Entity Framework V2 的時候只有實做出 ExecuteFunction<T> 方法,而到了 Entity Framework V4 才新增了一個不含泛型的 ExecuteFunction 方法,也就是因為這樣才讓 Entity Framework V4 的設計工具能自動產生沒有回傳值的 Function Imports 方法。 ( 如下圖在 Entity Framework V2 會找不到這個方法 )

當然在 Entity Framework V2 還是有方法能夠解決這個難題,以下這幾行就是在 Entity Framework V2 呼叫無回傳值預儲程序的方法:

EntityConnection entityConnection = (EntityConnection)ctx.Connection;

DbConnection storeConnection = entityConnection.StoreConnection;

try
{
    storeConnection.Open();

    using (DbCommand command = storeConnection.CreateCommand())
    {
        command.CommandText = "ResetData";
        command.CommandType = CommandType.StoredProcedure;
        command.ExecuteNonQuery();
    }
}
finally
{
    storeConnection.Close();
}

當然,這種作法也能夠執行任意 T-SQL 指令,算是跳脫 ORM 束搏的一種方法:

EntityConnection entityConnection = (EntityConnection)ctx.Connection;

DbConnection storeConnection = entityConnection.StoreConnection;

try
{
    storeConnection.Open();

    using (DbCommand command = storeConnection.CreateCommand())
    {
        command.CommandText = "DBCC CHECKIDENT ( Log, RESEED, 0)";
        command.CommandType = CommandType.Text;

        command.ExecuteNonQuery();
    }
}
finally
{
    storeConnection.Close();
}

註: 為了避免 Connection Leak 的問題,建議在撰寫這類程式時能用 try/finally 確保連線會被確實關閉。

另外,從 Entity Framework V4 開始也新增了兩個好用的方法,分別是:

透過這兩個方法可以更容易的透過 ObjectContext 物件執行在 Store 來源的任意 T-SQL 指令,使用上比 Entity Framework V2 還來的直覺,程式碼也更短,非常的實用。 :-)

相關連結