У меня есть куча вставок, которые я хочу иметь в транзакции, чтобы я мог откатиться в случае любых ошибок. Теперь моя проблема заключается в том, что для некоторых вставок мне нужен идентификатор предыдущей вставки. Однако выполнение 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
Lex 7 Мар 2018 в 19:25

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

3
KorsG 7 Мар 2018 в 16:34

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

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

А потом

int id = command.ExecuteScalar();
0
Aleks Andreev 7 Мар 2018 в 16:36

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

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

Как:

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

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

0
vedbhawsar 7 Мар 2018 в 16:35