简体   繁体   English

在C#中使用SqlTransaction,如何从存储过程中获取输出参数并插入到另一个表中?

[英]Using SqlTransaction in C#, how to get an output parameter from a stored procedure and insert into another table?

I have two tables: Table1 and Table2.我有两个表:Table1 和 Table2。 I need newly inserted Id (from Table1 ) as an output parameter which should be inserted into Table2 .我需要新插入的 Id(来自Table1 )作为应该插入Table2的输出参数。 And I must use SqlTransaction or TransactionScope here.我必须在这里使用SqlTransactionTransactionScope

Stored procedure:存储过程:

    CREATE PROC InsertTable1
    (
        @Name nvarchar(50),
        @OutputParam int out
    )
    AS
    BEGIN
        INSERT INTO Table1(Name) 
        VALUES(@Name)

        SELECT @OutputParam = SCOPE_IDENTITY() 
    END

C# code: C#代码:

SqlTransaction transaction = db.sqlconn.BeginTransaction();

SqlParameter[] param = new SqlParameter[2];
param[0] = new SqlParameter("@Name", "TestName");
param[1] = new SqlParameter("@OutputParam", SqlDbType.Int);
param[1].Direction = ParameterDirection.Output;

SqlHelper.ExecuteNonQuery(transaction, "InsertTable1", param);

int outputId = (int)param[1].Value;

When I run and debug the project I get an error当我运行和调试项目时出现错误

Object reference not set to an instance of an object未将对象引用设置为对象的实例

just after execution of就在执行之后

int outputId = (int)param[1].Value;

I think the transaction is closing the connection or something.我认为交易正在关闭连接或其他什么。 It works if I don't use transaction.如果我不使用事务,它会起作用。 But I have to use transaction anyhow.但无论如何我都必须使用事务。 I am open to any alternative ways to achieve the same result.我愿意接受任何替代方法来实现相同的结果。

For problems concerning transactions take a look TransactionScope class.有关事务的问题,请查看 TransactionScope 类。 Here is the intro part from microsoft documentation .这是微软文档的介绍部分。

The TransactionScope class provides a simple way to mark a block of code as participating in a transaction, without requiring you to interact with the transaction itself. TransactionScope 类提供了一种将代码块标记为参与事务的简单方法,而无需您与事务本身进行交互。 A transaction scope can select and manage the ambient transaction automatically.事务范围可以自动选择和管理环境事务。 Due to its ease of use and efficiency, it is recommended that you use the TransactionScope class when developing a transaction application.由于其易用性和效率,建议您在开发事务应用程序时使用 TransactionScope 类。

Also you have transaction properties ( TransactionInformation and Current ) at your disposal to investigate status of transaction while debugging.您还可以使用事务属性( TransactionInformationCurrent )在调试时调查事务状态。 This is all I can think of right now that wasn't suggested already.这是我现在能想到的所有尚未提出的建议。

First off, the overload of SqlHelper.ExecuteNonQuery you are using takes an array of parameter values , not an array of SqlParameter .首先,您正在使用的SqlHelper.ExecuteNonQuery的重载采用参数数组,而不是SqlParameter数组。 It only compiles and runs because the type is object .它只能编译和运行,因为类型是object So it will derive its own parameters via a SqlCommandBuilder and try to set the values on them from your param argument, but of course a SqlParameter cannot have a SqlParameter as its .Value .因此,它将通过SqlCommandBuilder派生自己的参数,并尝试从您的 param 参数中设置它们的值,但当然 SqlParameter 不能将 SqlParameter 作为其.Value The point is moot however, because the comments on the source code (below) specifically say you have no access to OUTPUT or RETURN values from this method.然而,这一点没有实际意义,因为对源代码的评论(下面)特别指出您无法从此方法访问 OUTPUT 或 RETURN 值。

    /// <summary>
    /// Execute a stored procedure via a SqlCommand (that returns no resultset) against the specified 
    /// SqlTransaction using the provided parameter values.  This method will query the database to discover the parameters for the 
    /// stored procedure (the first time each stored procedure is called), and assign the values based on parameter order.
    /// </summary>
    /// <remarks>
    /// This method provides no access to output parameters or the stored procedure's return value parameter.
    /// 
    /// e.g.:  
    ///  int result = ExecuteNonQuery(conn, trans, "PublishOrders", 24, 36);
    /// </remarks>
    /// <param name="transaction">a valid SqlTransaction</param>
    /// <param name="spName">the name of the stored procedure</param>
    /// <param name="parameterValues">an array of objects to be assigned as the input values of the stored procedure</param>
    /// <returns>an int representing the number of rows affected by the command</returns>
    public static int ExecuteNonQuery(SqlTransaction transaction, string spName, params object[] parameterValues)
    {
        //if we receive parameter values, we need to figure out where they go
        if ((parameterValues != null) && (parameterValues.Length > 0))
        {
            //pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
            SqlParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection.ConnectionString, spName);

            //assign the provided values to these parameters based on parameter order
            AssignParameterValues(commandParameters, parameterValues);

            //call the overload that takes an array of SqlParameters
            return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandParameters);
        }
        //otherwise we can just call the SP without params
        else
        {
            return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName);
        }
    }

USE OUTPUT clause to get inserted data and save into a temporary table. USE OUTPUT子句获取插入的数据并保存到临时表中。

Return that data from stored procedure从存储过程返回该数据

您不需要在输出中获取值,如果您想在另一个表中插入数据,在存储过程中,您可以轻松编写另一个插入查询,将这个 id 插入另一个表中

我可以看到您正在使用自定义 SqlHelper.ExecuteNonQuery 方法来执行查询,能否请您分享 SqlHelper.ExecuteNonQuery 方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM