Ошибка преобразования при преобразовании символьной строки в уникальный идентификатор при вставке значения в sql - PullRequest
1 голос
/ 22 апреля 2020

У меня есть простая SQL таблица с именем test, в которой есть два столбца. Первый столбец - это TINYINT, а второй - тип UNIQUEIDENTIFIER.

Я создал простой метод для вставки значений в таблицу «test». используется для l oop и работает нормально без каких-либо ошибок. Но как только я пытаюсь создать ошибку преобразования строки в uniqueidentifier, он откатит транзакцию и удалит все предыдущие вставленные значения в той же транзакции.

Это место, где происходит преобразование

strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";

Вот мой полный код

private static string TryThisPlease()
    {
        SqlConnection connection = null;
        SqlCommand command = null;
        SqlTransaction transaction = null;



        string strRet = "OK";



        try
        {
            connection = new SqlConnection(connectionString);
            connection.Open();



            //starting transaction mode
            transaction = connection.BeginTransaction(IsolationLevel.Snapshot);



            command = new SqlCommand("Test", connection);
            command.CommandType = CommandType.Text;
            command.Transaction = transaction;



            //for (int i = 255; i < 257; i++)
            for (int i = 250; i < 255; i++)
            {
                string[] strData = new string[] { "", "3" };



                string strCommand = "";



                //strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + Guid.NewGuid().ToString() + "'); ";
                strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";



                command.CommandText = strCommand;



                if (command.Connection.State != ConnectionState.Open)
                    command.Connection.Open();



                try
                {
                    command.ExecuteNonQuery();
                }
                catch (Exception EX)
                {
                    strRet = "FAIL";



                    try
                    {



                    }
                    catch (Exception)
                    {
                        strRet = "FAIL";
                    }
                }
            }



            transaction.Commit();
        }
        catch (Exception EX)
        {
            transaction.Rollback();



            strRet = "FAIL";
        }
        finally
        {
            connection.Close();
        }



        return strRet;
    }

Раскомментируя две закомментированные строки и комментируя строки ниже, происходит другая ошибка с той же серьезностью. В этом сценарии транзакции не откатываются

Есть ли способ предотвратить откат транзакции или я что-то пропустил в своем коде?

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

Если вы хотите, чтобы предыдущие вставки были успешными, вам нужно создать и зафиксировать транзакцию внутри foreach l oop, чтобы каждая строка считалась отдельной транзакцией.

using(SqlConnection connection = new SqlConnection(connectionString)) {

    connection.Open();

    for (int i = 250; i < 255; i++) {

        using(SqlCommand command = new SqlCommand("", connection, trans)) {
            command.CommandType = System.Data.CommandType.Text;

            using(SqlTransaction trans = connection.BeginTransaction()) {
                try {

                    strCommand = "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";

                    command.CommandText = strCommand;

                    command.ExecuteNonQuery();
                    trans.Commit();
                }
                catch(Exception e) {
                    //Handle Error
                    trans.Rollback();
                }
            }

        }

    }
}

Но ваша команда склонна к sql атакам с помощью инъекций. Я бы посоветовал вам параметризовать запрос, как указано ниже:

    SqlCommand cmd = new SqlCommand(
        "INSERT INTO Test(Test, Test2) VALUES(@id1,@id2)", conn);

cmd.Parameters.Add( new SqlParameter(@id1, SqlDbType.Int)).Value = i;
cmd.Parameters.Add( new SqlParameter(@id2, SqlDbType.Guid)).Value = (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString());

ОБНОВЛЕНИЕ Если вы все еще хотите go с пакетной транзакцией, вы можете рассмотреть точку сохранения для транзакции. Вместо отката всей транзакции вы можете выполнить откат до точки сохранения. Подробнее о точке сохранения

                        command.CommandText = strCommand;
                        trans.Save($"save{i}");
                        command.ExecuteNonQuery();
                        trans.Commit();
                    }
                    catch(Exception e) {
                        //Handle Error
                        trans.Rollback($"save{i}");
                        trans.Commit();
                    }
0 голосов
/ 22 апреля 2020

Проблема заключается в этом утверждении Guid.NewGuid().ToString().Remove(12, 1). Результат этого оператора удалит 12-й символ из вашего сгенерированного GUID, который не является действительным GUID, и, следовательно, сбой вставки базы данных.

Guid Format:
"00000000-0000-0000-0000-000000000000" 
             ^ 12th index character which will get removed from the Guid.

Когда условие i==251 становится истинным, этот код Guid.NewGuid().ToString().Remove(12, 1) будет выполнить, и это сгенерирует ошибку. Вам необходимо обновить его, чтобы получить GUID в правильном формате, чтобы решить вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...