2009-08-18 85 views
0

我正在使用.NET 3.5 SP1。如何在實體框架中獲取存儲過程@@ ERROR值?

我有一個存儲過程返回一個交易的結果如下圖所示:


Create PROCEDURE SetPrice 
    @itemId int, 
    @price int 
AS 
DECLARE @myERROR int -- Local @@ERROR 
     , @myRowCount int -- Local @@ROWCOUNT 
SET NOCOUNT ON 
BEGIN TRAN1 

UPDATE item_price_table SET [email protected] WHERE [email protected] 
UPDATE order_table SET [email protected] WHERE [email protected] 
SELECT @myERROR = @@ERROR, @myRowCount = @@ROWCOUNT 
IF @myERROR != 0 GOTO HANDLE_ERROR 
COMMIT TRAN1 -- No Errors, so go ahead 
RETURN 0 
HANDLE_ERROR: 
    ROLLBACK TRAN1 
    RETURN @myERROR 

我試圖讓@@ ERROR狀態代碼返回。在EF V1,I創建FunctionImport 'SetPrice' 和通過創建在 'mycontext' 類方法稱之爲如下所示:


public int SetPrice(int itemId, int price) {  
Int32 result = -1; 
EntityCommand cmd = ((EntityConnection)this.Connection).CreateCommand(); 
cmd.CommandType = System.Data.CommandType.StoredProcedure; 
cmd.CommandText = "myContext.SetPrice"; 
cmd.Parameters.AddWithValue("itemId", itemId); 
cmd.Parameters.AddWithValue("price", price); 
EntityParameter retParameter = new EntityParameter(); 
retParameter.Direction = System.Data.ParameterDirection.ReturnValue; 
cmd.Parameters.Add(retParameter); 
cmd.Connection.Open(); 
cmd.ExecuteNonQuery(); 
result = Convert.ToInt32(retParameter.Value); 
cmd.Connection.Close(); 
return result; 
} 

這導致以下錯誤:

The data reader returned by the store data provider does not have enough columns for the query requested. at System.Data.EntityClient.EntityCommandDefinition.ConstantColumnMapGenerator.System.Data.EntityClient.EntityCommandDefinition.IColumnMapGenerator.CreateColumnMap(DbDataReader reader) at System.Data.EntityClient.EntityCommandDefinition.Execute(EntityCommand entityCommand, CommandBehavior behavior) at System.Data.EntityClient.EntityCommand.ExecuteReader(CommandBehavior behavior) at System.Data.EntityClient.EntityCommand.ExecuteScalar[T_Result](Func`2 resultSelector) at System.Data.EntityClient.EntityCommand.ExecuteScalar() 

請告訴如何解決問題。

謝謝。

回答

1

EF v1在從存儲過程返回標量值時存在問題。 This thread有更多信息。

1

答案很長,但對於SQL 2005+,您不需要使用@@ ERROR。對於SQL Server 2000,您需要使用不同的...因爲您使用的是存儲過程,所以如果您在Windows上使用實體框架或在Solaris上使用jTDS,則無關緊要...

(順便說一句, SQL無論如何是有缺陷的)

如果第一次更新失敗,這可能不會捕獲錯誤。 @@ ERROR有隻有最後一條語句的值:

UPDATE item_price_table SET [email protected] WHERE i[email protected] 
UPDATE order_table SET [email protected] WHERE [email protected] 
SELECT @myERROR = @@ERROR, @myRowCount = @@ROWCOUNT 

你需要每一個DDL語句後檢查:

UPDATE item_price_table SET [email protected] WHERE [email protected] 
SELECT @myERROR = @@ERROR, @myRowCount = @@ROWCOUNT 
IF @myERROR <> 0 GOTO HANDLE_ERROR 

UPDATE order_table SET [email protected] WHERE [email protected] 
SELECT @myERROR = @@ERROR, @myRowCount = @@ROWCOUNT 
IF @myERROR <> 0 GOTO HANDLE_ERROR 

然而,這仍然是沒有用的。然後,您可以重新拋出的使用RAISERROR和客戶端只需要知道一個例外發生了:

... 
HANDLE_ERROR: 
    ROLLBACK TRAN1 
    RAISERROR ('Oops: %i', 16, 1, @myERROR) --to pass error number if you really want 

或者乾脆用try/catch語句在SQL Server 2005+。在catch塊中的RAISERROR

無論如何,無論哪種情況,您都不需要讀取@@ ERROR或返回值......您依賴於被捕獲的SQLException。對我來說,存儲過程返回有意義的數據或異常(並且任何數據被忽略或無效)

PS:爲什麼在不使用時存儲@@ ROWCOUNT?

+0

+1完全同意,@@ ERROR在許多方面令人難以置信。 – 2009-08-18 21:17:39

+0

謝謝。 我已經創建了示例存儲過程來探索EF v1中的SP支持。 – dev 2009-08-19 22:11:20

0

謝謝。正如那篇文章中提到的那樣,SELECT語句是必需的。 在RETURN之前添加SELECT時,查詢正確執行。