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.