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

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

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

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

	RETURN
```

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

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/726c2992c902d7e32c24-image_665.png)

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/072564398549cd6967b2-SNAGHTML9348d12.png)

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

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/80efb0353f8440fa134b-image_666.png)

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

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/980dee41825b1de98373-SNAGHTML92e9443.png)

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

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/dc33649457cf4e18bc01-image_667.png)

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

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

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/dbe7eaa0eb29c31f3bcf-image_668.png)

在 Entity Framework V2 的時候只有實做出 [ExecuteFunction<T>](http://msdn.microsoft.com/zh-tw/library/bb739018\(VS.90\).aspx) 方法，而到了 Entity Framework V4 才新增了一個不含泛型的 [ExecuteFunction](http://msdn.microsoft.com/en-us/library/dd986915.aspx) 方法，也就是因為這樣才讓 Entity Framework V4 的設計工具能自動產生沒有回傳值的 Function Imports 方法。 ( 如下圖在 Entity Framework V2 會找不到這個方法 )

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/b75ac505200c2ccaf5a2-image_669.png)

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

```csharp
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 束搏的一種方法：

```csharp
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 開始也新增了兩個好用的方法，分別是：

-   [ExecuteStoreCommand](http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.executestorecommand.aspx)
-   [ExecuteStoreQuery<T>(String, Object\[\])](http://msdn.microsoft.com/en-us/library/dd487208.aspx)

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

**相關連結**

-   [ADO.Entity Framework: Stored Procedure Customization](https://learn.microsoft.com/en-us/archive/blogs/meek/ado-entity-framework-stored-procedure-customization)
-   [Entity Framework 4.0: Scalar and Void Functions](https://web.archive.org/web/20160311075139/http://danrigsby.com/blog/index.php/2009/05/20/entity-framework-40-scalar-and-void-functions)
-   [HOW TO：匯入預存程序](http://msdn.microsoft.com/zh-tw/library/bb896231\(VS.90\).aspx)  /  [How to: Import a Stored Procedure](http://msdn.microsoft.com/en-us/library/bb896231\(VS.90\).aspx)   ( Visual Studio 2008 )
-   [ObjectContext.ExecuteFunction Method (String, ObjectParameter\[\])](http://msdn.microsoft.com/en-us/library/dd986915.aspx)
-   [Tuning Up ADO.NET Connection Pooling in ASP.NET Applications](https://www.codeguru.com/dotnet/tuning-up-ado-net-connection-pooling-in-asp-net-applications/)
-   [Entity Framework v1 and v2](http://geekswithblogs.net/iupdateable/archive/2009/03/25/entity-framework-v1-and-v2.aspx)
-   [What's New and Cool in Entity Framework 4.0](https://web.archive.org/web/20140209145601/http://www.develop.com:80/entityframework4)
