Лучше ли передавать открытый SqlConnection в качестве параметра или вызывать новый в каждом методе?
Если методы/функции, которые я собираюсь вызвать, связаны с необходимостью открытого SqlConnection, я открою это в методе, который вызывает функцию. Например:
protected static void btnSubmit(){
conn.Open();
myMethod(someParam, conn);
conn.Close();
}
protected static void myMethod(object someParam, SqlConnection conn){
//Some SQL commands etc here..
}
Я делаю это так, чтобы я:
- Только открывать и закрывать 1 SqlConnection для процесса
Однако было бы лучше структурировать мой код так:
protected static void btnSubmit(){
myMethod(someParam);
}
protected static void myMethod(object someParam){
SqlConnection conn = New SqlConnection(".....");
conn.Open();
//Some SQL commands etc here..
conn.Close();
}
Преимущество, которое я вижу в его структурировании, таково:
- Мне не нужно передавать дополнительный параметр для каждого метода
- Если позже в строке метод больше не имеет команды SQL, каждый раз, когда не будет вызываться неиспользуемый параметр
Недостаток, который я вижу в этом, заключается в следующем:
- Если
myMethod
является рекурсивным методом, тогда, когда он вызывает себя, он собирается открыть еще один SqlConnection
и т.д. и т.д.
- Если
btnSubmit
вызывает несколько методов, для которых все требуют SqlConnection, каждый из них собирается открыть и закрыть новое соединение.
Каков наилучший способ сделать это, и который наиболее часто практикуется?
Ответы
Ответ 1
ADO.NET использует пул соединений, поэтому он автоматически использует существующие открытые соединения, даже если вы думаете, что открываете новое соединение. Имея это в виду, нет никакой причины передавать соединение через ваш код (в качестве параметра). Это сделает ваш код намного чище, с той же производительностью, что и при передаче соединения в качестве параметра.
Подробнее здесь
Также (и это действительно важно), пожалуйста, используйте ключевое слово "using". Таким образом, вам не придется иметь дело с закрытием соединения и очисткой, потому что ваш код в том виде, в котором он написан сейчас, не имеет отношения к закрытию соединений, так что в случае какого-то исключения вы можете столкнуться с нарушением лимита соединений на вашем сервере., Перейти с чем-то вроде этого:
using(var connection = new SqlConnection(<connection_string>))
{
connection.Open();
using(var command = connection.CreateCommand())
{
}
}
Как видите, нет необходимости вызывать connection.Close() или обрабатывать исключения и закрывать соединение в вашем блоке finally
, потому что это "задание" для блока "using".
Кроме того, одно важное замечание... транзакции не передаются с помощью опроса соединения, поэтому, если вы хотите, чтобы ваша транзакция проходила через вызовы методов, вам придется пропустить ваше соединение (и это единственная причина, по которой я могу подумать, почему вы должны делать это). это).
Ответ 2
Лучший шаблон для использования - Repository + UnitOfWork.
Таким образом создается репозиторий и передается UnitOfWork, который содержит соединение. После выполнения работы UnitOfWork удаляется.
// Pseudocode
using(UnitOfWork uow = new UnitOfWork())
{
Repository.Init(uow);
Repository.SaveInDb(stuff);
}
И Единица работы:
// PseudoCode
class UnitOfWork : IDisposable
{
public UnitOfWork()
{
conn = new SqlConnection();
conn.Open();
}
public void Dispose()
{
conn.Close();
}
....
}
Это то, что я всегда использую.
Некоторые люди предпочитают более простой подход, когда репозиторий владеет соединением. Это проще, но если вам нужно иметь транзакцию через несколько репозиториев, она не будет работать.