Повторное использование SqlConnection в методе DAL - PullRequest
0 голосов
/ 15 июля 2010

Предположим, у нас есть метод DAL

public void BuyProduct(int productId, int quantity, int buyerId);

В этом методе нам нужно вызвать 2 хранимые процедуры:

  1. EXEC tblOrders_CreateNewOrder
  2. EXEC tblProducts_RecalculateStock

Является ли хорошей практикой создание 2 SqlCommands - по одной на хранимую процедуру и использование одного SqlConnection для выполнения этих команд?

OR

Лучше ли создавать отдельную SqlConnection для каждой SqlCommand?

Поэтому в основном я спрашиваю: является ли хорошей практикой повторное использование одной SqlConnection для нескольких (2-4) SqlCommands в одном методе DAL (очевидно, что повторное использование SqlConnection во всем DAL будет глупым)

PS - пожалуйста, не спрашивайте меня, почему я не могу просто объединить 2 хранимые процедуры в 1. Мой ответ - разделение проблем.

Ответы [ 4 ]

5 голосов
/ 15 июля 2010

Настоящая проблема не в связи, а в транзакциях. Когда логическая операция включает в себя несколько физических операций DAL, обычно они должны быть частью транскрипции. Если ядро ​​не является необязательным ... Если транзакция охватывает несколько соединений, то она должна быть преобразована в распределенную транзакцию с катастрофическими результатами производительности. Поэтому при разработке DAL всегда стремитесь связать транзакцию с соединением. Это отражается на дизайне DAL API, поскольку обычно это приводит к тому, что объекты подключения и транзакции должны быть явно переданы методам DAL, либо в виде отдельных параметров, либо в качестве объекта «контекста», который их объединяет.

2 голосов
/ 15 июля 2010

Да, хорошей практикой является повторное использование одного SqlConnection для нескольких SqlCommands (в ​​пределах одного метода). Как я понял, в вашем случае вам также нужно использовать SqlTransaction так:

public void SomeDALMethod(string connectionString)
{
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();

        var transaction = connection.BeginTransaction();

        var command1 = new SqlCommand("tblOrders_CreateNewOrder", connection, transaction)
                        {
                            CommandType = CommandType.StoredProcedure
                        };
        var command2 = new SqlCommand("tblProducts_RecalculateStock", connection, transaction)
                        {
                            CommandType = CommandType.StoredProcedure
                        };

        try
        {
            command1.ExecuteNonQuery();
            command2.ExecuteNonQuery();
            transaction.Commit();
        }
        catch (Exception ex)
        {
            // Commit failed
            try
            {
                transaction.Rollback();
            }
            catch (Exception ex2)
            {
                // Rollback failed
            }
        }           
    }
}

Позволяет откатить выполнение первой хранимой процедуры в случае сбоя второго sp.

1 голос
/ 15 июля 2010

По умолчанию .NET создает пул SqlConnection.Таким образом, создание новых соединений (при условии, что все они используют одну и ту же строку соединения) не приводит к издержкам, пока пул не будет полностью исчерпан.

0 голосов
/ 17 ноября 2012

Этот метод содержит соединение и просто меняет параметры при каждой итерации. Просто передайте ему свою обычную информацию и делегата, который возвращает список параметров, в основном просто рассказывая, как построить список параметров. Тип T - это тип объекта, из которого вы строите список параметров. Он возвращает false только в случае сбоя всех элементов.

public static bool ExecuteBulkNonQuery<T>(string connectionString, CommandType commandType, 
            string commandText, IEnumerable<T> listItems, Func<T,SqlParameter[]> setParameters)
        {
            var fails = 0;
            using (var conn = new SqlConnection(connectionString))
            {
                using (var comm = new SqlCommand(commandText, conn))
                {
                    comm.CommandType = commandType;
                    conn.Open();
                    foreach (var obj in listItems)
                    {
                        comm.Parameters.Clear();
                        comm.Parameters.AddRange(setParameters.Invoke(obj));
                        fails += comm.ExecuteNonQuery();
                    }
                    return fails != 0;
                }
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...