使用FK将事务内的行插入到创建的第一行

时间:2017-10-05 14:35:13

标签: c# sql sql-server transactions

我有一批需要在一个事务中插入的行,第一行是标题,所有后续行必须引用第一行。

这就是我试图插入第一行的方式:

using ( var connection = new SqlConnection( _connectionString ) )
{
    connection.Open();
    var transaction = connection.BeginTransaction();

    try
    {
        // create the record header
        using ( var createRecordCommand = connection.CreateCommand() )
        {
            createRecordCommand.CommandText =
                "DECLARE @RecordId INT;" +
                $"INSERT INTO ..." +
                "SET @RecordId = scope_identity();";

            createRecordCommand.Transaction = transaction;
            createRecordCommand.ExecuteNonQuery();

我在后续语句中努力引用RecordId,似乎认为变量@RecordId未在下面的代码段中声明。 '必须声明标量变量“@RecordId”。'

using ( var createAttributeCommand = connection.CreateCommand() )
{
    createAttributeCommand.Transaction = transaction;

    createAttributeCommand.CommandText =
        $"INSERT INTO ... (RecordId,...) VALUES (@RecordId,...)";

同时将@RecordId变量作为参数提取也很困难,当我将下面的行与DECLARE @RecordId INT;

结合使用时,它不喜欢它
createRecordCommand.Parameters.Add( new SqlParameter( "@RecordId", SqlDbType.Int ) { Direction = ParameterDirection.Output } );

1 个答案:

答案 0 :(得分:0)

我没有意识到你可以在事务提交之前提取数据,假设因为ExecuteScalar()不起作用,我会遇到同样的问题。

正如评论中指出的那样,存储过程可能是最好的解决方案,SQL专家听起来像一段时间后破碎的记录; p。这将是短期过于复杂,因为存在变量参数,验证和值将根据业务逻辑进行变异。作为一个团队,我们在C#中更加自如,因此逻辑将保持不变,直到完全被确定为止。

结果代码如下, N.B。在实际代码中,将所有变量作为参数传递以避免SQL注入,我们是,这只是演示

using ( var connection = new SqlConnection( _connectionString ) )
{
    connection.Open();
    var transaction = connection.BeginTransaction();

    try
    {
        // create the record header
        using ( var createRecordCommand = connection.CreateCommand() )
        {
            createRecordCommand.CommandText =
                //"DECLARE @RecordId INT;" + 
                $"INSERT INTO ..." +
                "SET @RecordId = scope_identity();";

            createRecordCommand.Transaction = transaction;
            createRecordCommand.Parameters.Add( new SqlParameter( "@RecordId", SqlDbType.Int ) { Direction = ParameterDirection.Output } );
            createRecordCommand.ExecuteNonQuery();

            recordId = (int) createRecordCommand.Parameters["@RecordId"].Value;

// ...

using ( var createAttributeCommand = connection.CreateCommand() )
{
    createAttributeCommand.Transaction = transaction;
    createAttributeCommand.CommandText =
        $"INSERT INTO ... (RecordId,...) VALUES ({recordId},...)";

// ...

transaction.Commit();