C# Получение вставленного идентификатора внутри транзакции

У меня есть куча вставок, которые я хочу иметь в транзакции, чтобы я мог откатиться в случае любых ошибок. Теперь моя проблема в том, что для некоторых вставок мне нужен идентификатор предыдущей вставки. Тем не менее, делая var id = (int)command.ExecuteScalar(); выдает исключение ("Ссылка на объект не установлена ​​на экземпляр объекта"). Если я бегу command.ExecuteScalar() без попытки присвоить результат, код работает отлично. Можно ли получить идентификатор до совершения транзакции? Если нет, каковы мои альтернативы?

Мой код:

using (SqlConnection connection = new SqlConnection("ConnectionHere")
{
            connection.Open();

            SqlCommand command = connection.CreateCommand();
            SqlTransaction transaction;

            // Start a local transaction.
            transaction = connection.BeginTransaction();
            command.Connection = connection;
            command.Transaction = transaction;

            try
            {                    
                string insertStudent = "INSERT INTO Students (FirstName, MiddleName, LastName)" +
                " VALUES (@firstName, @middleName, @lastName)";

                command.CommandText = insertStudent;
                command.Parameters.AddWithValue("@firstName", application.FirstName);
                command.Parameters.AddWithValue("@middleName", application.MiddleName);
                command.Parameters.AddWithValue("@lastName", application.LastName);

                var id = (int) command.ExecuteScalar();//EXCEPTION THROWN HERE

                // Attempt to commit the transaction.
                transaction.Commit();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
                Console.WriteLine("  Message: {0}", ex.Message);

                // Attempt to roll back the transaction.        
                transaction.Rollback();
            }
}

3 ответа

Решение

Я предполагаю, что столбец в таблице "Студенты" настроен как столбец идентификаторов и что вы используете SQL Server 2008+.

В этом случае вам нужно изменить оператор SQL, чтобы он возвращал вставленное значение идентификатора, например так:

  string insertStudent = "INSERT INTO Students (FirstName, MiddleName, LastName)" +
            " VALUES (@firstName, @middleName, @lastName);" +
            " SELECT SCOPE_IDENTITY();";

Дополнительную информацию о SCOPE_IDENTITY можно найти здесь: https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql

Используйте этот синтаксис SQL, чтобы получить вставленный идентификатор:

INSERT INTO Students (FirstName, MiddleName, LastName) OUTPUT Inserted.ID .... 

А потом

int id = command.ExecuteScalar();

Просто поменяй код

  var id = (int) command.ExecuteScalar();

как:

int id = Convert.ToInt32(cmd.ExecuteScalar());

Это гарантирует, что даже если ExecuteScalar вернет значение NULL, в результате отсутствия выбора в хранимой процедуре значение countDis будет равно 0. Поскольку Convert.ToInt32(null) = 0.

Другие вопросы по тегам