2010-07-15 3 views
0

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

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

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

  1. EXEC tblOrders_CreateNewOrder
  2. EXEC tblProducts_RecalculateStock

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

ИЛИ

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

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

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

ответ

5

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

+0

Спасибо Ремусу. Я полагаю, что нормально использовать SqlConnection в DAL-методе, если правильность транзакции является необязательной (это точно мой случай). – niaher

1

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

+0

Правда, однако, SqlConnection.Open() является дорогостоящей операцией, и я предпочитаю называть ее один раз, а не 2-4 раза в рамках одного метода DAL. – niaher

+1

Вы можете, конечно, использовать его. Единственное замечание состоит в том, что нельзя слишком долго простаивать объект. Если вы вызываете два сохраненных процесса последовательно, вы, конечно, можете использовать один и тот же SqlConnection. – Kangkan

2

Да, это хорошая практика для повторного использования одного 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 
      } 
     }   
    } 
} 

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

+0

Спасибо за пример кода.Кстати, почему вы используете var, а не фактический тип? – niaher

+0

@niaher: это короче. Сравнить 'Dictionary d = new Dictionary ()' и 'var d = new Dictionary ()'. – bniwredyc

0

Этот метод содержит соединение и просто изменяет параметры с каждой итерацией. Просто подайте свою обычную информацию и делегат, который возвращает список параметров, в основном просто рассказывая, как построить список параметров. Тип 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; 
       } 
      } 
     } 
Смежные вопросы