Откат и уведомление, если что-то идет не так в транзакции SQL - PullRequest
0 голосов
/ 17 марта 2019

Имел код, который выполнял транзакцию в формах Windows через SqlTransaction и загружал таблицу с базой данных. Если произошла ошибка, она просто выводилась в MessageBox.Show(ex.Message);. Однако теперь необходимо обрабатывать данные на стороне сервера базы данных в форме процедуры. Но как мне сообщить пользователю, что данные в транзакции были неверны в приложении?

ALTER PROCEDURE [dbo].[addPacient]
    @name NVARCHAR(20),
    @surname NVARCHAR(20),
    @middle NVARCHAR(20),
    @passport NCHAR(10),
    @address NVARCHAR(20),
    @age INT,
    @name_diagnoz NVARCHAR(30),
    @stage CHAR(1)
AS
BEGIN TRAN  
    BEGIN TRY
        INSERT INTO Pacient(Name, Surname, Middle_name, Column__Passport,
                            Legal_address_Clinic, Age, id_diagnoz)
        VALUES (@name, @surname, @middle, @passport, 
                @address, @age, 
                (SELECT id_diagnoz FROM Diagnoz 
                 WHERE Name_diagnoz = @name_diagnoz and Stage = @stage))
    END  TRY
    BEGIN CATCH
        ROLLBACK TRAN

        RETURN
    END CATCH   
COMMIT TRAN

Как это называется:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    SqlCommand command = new SqlCommand("addPacient", connection);
    command.CommandType = CommandType.StoredProcedure;

    command.Parameters.AddWithValue("@name", txtName.Text);
    command.Parameters.AddWithValue("@surname",  txtSurname.Text);
    command.Parameters.AddWithValue("@middle",  txtMiddle.Text);
    command.Parameters.AddWithValue("@passport",  mskPassport.Text);
    command.Parameters.AddWithValue("@address",  cbAddres.Text);
    command.Parameters.AddWithValue("@age",  cbAge.Text);
    command.Parameters.AddWithValue("@name_diagnoz", cbxNameDiagnoz.Text);
    command.Parameters.AddWithValue("@stage", cbxStage.Text);

    connection.Open();

    using (SqlDataReader dr = command.ExecuteReader())
    {
        while (dr.Read())
        {
            int intColumn = dr.GetInt32(dr.GetOrdinal("intColumnName"));
            string stringColumn = dr.GetString(dr.GetOrdinal("stringColumnName"));
        }
    }
}

1 Ответ

1 голос
/ 17 марта 2019

Нет необходимости в явной транзакции в вашем текущем коде; одна транзакция автоматического подтверждения оператора предоставит все-ничего и вызовет ошибку по умолчанию. В этом случае T-SQL TRY / CATCH не предоставляет значения, поэтому вы можете просто использовать:

ALTER PROCEDURE [dbo].[addPacient]
    @name NVARCHAR(20),
    @surname NVARCHAR(20),
    @middle NVARCHAR(20),
    @passport NCHAR(10),
    @address NVARCHAR(20),
    @age INT,
    @name_diagnoz NVARCHAR(30),
    @stage CHAR(1)
AS
INSERT INTO Pacient(Name, Surname, Middle_name, Column__Passport,
    Legal_address_Clinic, Age, id_diagnoz)
VALUES (@name, @surname, @middle, @passport, 
    @address, @age, 
        (SELECT id_diagnoz FROM Diagnoz 
    WHERE Name_diagnoz = @name_diagnoz and Stage = @stage));
GO

Если у вас есть несколько операторов, которые выполняют модификации данных в явной транзакции T-SQL, убедитесь, что вы включили SET XACT_ABORT ON в коде proc, чтобы обеспечить автоматический откат транзакции в случае тайм-аута клиента (где блок CATCH не выполнит). Я предлагаю этот шаблон обработки ошибок в процедурах с несколькими утверждениями:

ALTER PROCEDURE [dbo].[addPacient]
    @name NVARCHAR(20),
    @surname NVARCHAR(20),
    @middle NVARCHAR(20),
    @passport NCHAR(10),
    @address NVARCHAR(20),
    @age INT,
    @name_diagnoz NVARCHAR(30),
    @stage CHAR(1)
AS
SET XACT_ABORT ON;
BEGIN TRY
    BEGIN TRAN;
    INSERT INTO Pacient(Name, Surname, Middle_name, Column__Passport,
        Legal_address_Clinic, Age, id_diagnoz)
    VALUES (@name, @surname, @middle, @passport, 
        @address, @age, 
            (SELECT id_diagnoz FROM Diagnoz 
        WHERE Name_diagnoz = @name_diagnoz and Stage = @stage));
    --other data modification statements
    COMMIT;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK;
    THROW;
END CATCH;
GO

Кроме того, лучше избегать AddWithValue и передавать строго типизированные параметры. Это улучшит повторное использование кэша на стороне сервера, а также предоставит другие преимущества .

try
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    using (SqlCommand command = new SqlCommand("addPacient", connection))
    {
        command.CommandType = CommandType.StoredProcedure;

        command.Parameters.Add("@name", SqlDbType.NVarChar, 20).Value = txtName.Text;
        command.Parameters.Add("@surname", SqlDbType.NVarChar, 20).Value = txtSurname.Text;
        command.Parameters.Add("@middle", SqlDbType.NVarChar, 20).Value  = txtMiddle.Text;
        command.Parameters.Add("@passport", SqlDbType.NChar, 10).Value = mskPassport.Text;
        command.Parameters.Add("@address", SqlDbType.NVarChar, 20).Value = cbAddres.Text;
        command.Parameters.Add("@age", SqlDbType.Int, 20).Value = int.Parse(cbAge.Text);
        command.Parameters.Add("@name_diagnoz", SqlDbType.NVarChar, 30).Value = cbxNameDiagnoz.Text;
        command.Parameters.Add("@stage", SqlDbType.Char, 1).Value = cbxStage.Text;

        connection.Open();

        using (SqlDataReader dr = command.ExecuteReader())
        {
            while (dr.Read())
            {
                int intColumn = dr.GetInt32(dr.GetOrdinal("intColumnName"));
                string stringColumn = dr.GetString(dr.GetOrdinal("stringColumnName"));
            }
        }
    }
}
catch (Exception ex)
{
    MessageGox.Show(ex.Message);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...