【问题标题】:Strongly-typed dataset not retrieving return value from stored procedure强类型数据集未从存储过程中检索返回值
【发布时间】:2012-08-03 04:53:33
【问题描述】:

我有一个强类型数据集,它使用 DBDirectMethods 通过调用存储过程将数据插入数据库。存储过程返回新创建记录的主键。这是一个示例存储过程:

CREATE PROCEDURE dbo.CreateUser
(
    @UserName   VARCHAR(50)
    @Password   VARCHAR(50)
)
AS

SET NOCOUNT OFF

DECLARE @UserID INT

BEGIN TRANSACTION

INSERT INTO dbo.Users (UserName, Password) VALUES (@UserName, @Password)

SET @UserID = SCOPE_IDENTITY()

INSERT INTO dbo.Users_History (UserID, Status, TimeStamp) VALUES (@UserID, 'C', GETUTCDATE())

COMMIT TRANSACTION

RETURN @UserID

GO

如果我从 SSMS 执行存储过程,则会创建用户帐户、更新历史记录表并返回主键。如果我使用强类型数据集运行我的应用程序并让 SQL Profiler 运行,我可以看到相同的代码正在执行;但是,数据集返回 -1 作为主键并破坏应用程序。

在 VS 生成的表格适配器代码中,相关行是:

this._adapter.InsertCommand.CommandText = "dbo.CreateUser";
this._adapter.InsertCommand.CommandType = global::System.Data.CommandType.StoredProcedure;
this._adapter.InsertCommand.Parameters.Add(new global::System.Data.SqlClient.SqlParameter("@RETURN_VALUE", global::System.Data.SqlDbType.Int, 4, global::System.Data.ParameterDirection.ReturnValue, 10, 0, null, global::System.Data.DataRowVersion.Current, false, null, "", "", ""));
this._adapter.InsertCommand.Parameters.Add(new global::System.Data.SqlClient.SqlParameter("@UserName", global::System.Data.SqlDbType.VarChar, 50, global::System.Data.ParameterDirection.Input, 0, 0, "UserName", global::System.Data.DataRowVersion.Current, false, null, "", "", ""));
this._adapter.InsertCommand.Parameters.Add(new global::System.Data.SqlClient.SqlParameter("@Password", global::System.Data.SqlDbType.VarChar, 50, global::System.Data.ParameterDirection.Input, 0, 0, "Password", global::System.Data.DataRowVersion.Current, false, null, "", "", ""));

try {
    int returnValue = this.Adapter.InsertCommand.ExecuteNonQuery();
    return returnValue;
}
finally {
    if ((previousConnectionState == global::System.Data.ConnectionState.Closed)) {
        this.Adapter.InsertCommand.Connection.Close();
    }
}

这只是 VS 通常生成的标准样板代码 - 没有任何内容是手动编辑的。它只是没有获取返回值。

我正在运行带有 SQL 2008 R2 SP1 Express 的 Windows 7。

【问题讨论】:

    标签: c# stored-procedures ado.net strongly-typed-dataset


    【解决方案1】:

    看来,我需要返回整个新记录,而不是只返回 PK。通过将我的存储过程更改为以下内容:

    CREATE PROCEDURE dbo.CreateUser
    (
        @UserName   VARCHAR(50)
        @Password   VARCHAR(50)
    )
    AS
    
    SET NOCOUNT OFF
    
    DECLARE @UserID INT
    
    BEGIN TRANSACTION
    
    INSERT INTO dbo.Users (UserName, Password) VALUES (@UserName, @Password)
    
    SET @UserID = SCOPE_IDENTITY()
    
    INSERT INTO dbo.Users_History (UserID, Status, TimeStamp) VALUES (@UserID, 'C', GETUTCDATE())
    
    COMMIT TRANSACTION
    
    SELECT UserID, UserName, Password FROM dbo.Users WHERE UserID = @UserID
    
    GO
    

    然后 ADO.NET 会自动将返回的结果加载到数据集中,我可以从那里获取 UserID。

    【讨论】:

    • 请注意,您也可以执行 SELECT UserID,然后,您可以执行 ExecuteScalar 并将结果转换为 Int32,而不是 ExecuteNonQuery。 - 例如int userId = Convert.ToInt32(Adapter.InsertCommand.ExecuteScalar());
    【解决方案2】:

    您需要将查询类型从 ExecuteNonQuery 更改为 ExecuteScalar 见http://blogs.msdn.com/b/smartclientdata/archive/2005/10/31/returnidentityvaluequery.aspx

    【讨论】:

      【解决方案3】:

      根据记忆,这里的问题是ExecuteNonQuery() 返回的值是受查询影响的行数。

      相反,您的返回值应该可以通过以下方式访问:

      InsertCommand.Parameters["@RETURN_VALUE"].Value;
      

      InsertCommand.Parameters[0].Value;
      

      此外,您可以尝试将返回参数名称更改为 @UserID 而不是 @RETURN_VALUE,但它应该仍然可以正常工作。

      【讨论】:

      • 返回值的设置由生成的代码负责,如果我从存储过程中删除 SET NOCOUNT ON,该值会正确加载受影响的行数(即 2) ;但是如果我尝试返回任何其他值,那么它会失败。不过,我已经制定了一个解决方案(见下文)。
      • 返回值在参数中——这是自动生成代码的一个弱点——它并不真正关心输出和返回参数。如果您想单独依赖自动生成的代码,您的解决方案可能是最好的解决方案。
      • ExecuteScalar 似乎是要走的路。
      猜你喜欢
      • 2012-10-06
      • 1970-01-01
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      • 2010-09-10
      • 2020-03-27
      • 1970-01-01
      相关资源
      最近更新 更多