Обычно я не рекомендую использовать один экземпляр SqlConnection для нескольких запросов.Даже если вы включите MARS , у вас могут возникнуть проблемы с производительностью.Я думаю, что когда ваше соединение получает команду не для чтения, буфер соединения приостановит все текущие чтения, пока запись не закончится.Единственное, что вы действительно экономите, это время, которое требуется для установления соединения.
SqlConnections pooled , поэтому вы можете настроить провайдера так, чтобы минимальное / максимальное количество экземпляров было доступно длявымогательство клиентов.Имейте в виду, что это также контролируется любой базой данных, к которой вы подключаетесь;при условии, что вы подключаетесь к экземпляру SQL Server, SQL Server имеет собственную настройку максимального допустимого количества подключений.
Вместо того, чтобы разрешать клиентам определять, когда открывать / закрывать общий экземпляр SqlConnection, я предлагаю, чтобы ваши открытые члены принялилибо в командной строке, либо в параметрах команды.Затем, аналогично тому, что было предложено в вашем примере, откройте соединение из пула и выполните команду.
public IEnumerable<SqlResults> ExecuteStoredProcedure(string procedure, params SqlParameter[] parameters) {
using(SqlConnection connection = new SqlConnection(MyConnectionStringProperty)) {
try {
connection.Open();
using(SqlCommand command = new SqlCommand(procedure, connection)) {
command.CommandType = CommandType.StoredProcedure;
if(parameters != null) {
command.Parameters.AddRange(parameters);
}
// yield return to handle whatever results from proc execution
// can also consider expanding to support reader.NextResult()
using(SqlDataReader reader = command.ExecuteReader()) {
yield return new SqlResults {
Reader = reader;
};
}
}
}
finally {
if(connection.State != ConnectionState.Closed) {
connection.Close();
}
}
}
}
Пример кода выше - это просто пример концепции, которую я использую на работе.Пример теперь имеет максимальную обработку ошибок, но очень гибок в том, как возвращаются и обрабатываются результаты.Класс SqlResults
просто содержит свойство SqlDataReader
и может быть расширен для включения ошибок.
Если сделать что-либо из этого static
, все будет хорошо, если вы включите способ созданияодноэлементный экземпляр класса провайдера, и он по-прежнему не имеет изменяемых свойств, которые могут быть общими (потенциально для различных запросов / потоков).Возможно, вы захотите рассмотреть какой-нибудь подход IoC или Dependency Injection для предоставления строки подключения по вашему запросу.
EDIT
Выход позволяет вызывающей стороне использовать возвращенный объектперед тем, как контекст выполнения возвращается к методу, дающему возврат для продолжения выполнения.Таким образом, в приведенном выше примере вызывающая сторона может сделать что-то вроде этого:
// Since it's an IEnumerable we can handle multiple result sets
foreach(SqlResults results in MySqlHelper.ExecuteStoredProcedure(myProcedureName, new SqlParameter("myParamName", myParamValue)) {
// handle results
}
без закрытия соединения, пока мы обрабатываем результаты.Если вы заметили в примере, у нас есть using
операторов для наших SqlClient
объектов.Этот подход позволяет отделить обработку результирующего набора от MySqlHelper
, поскольку класс провайдера позаботится о возможном дублировании кода предоставления SQL, делегирует обработку результата вызывающей стороне, а затем продолжит то, что он должен делать (т.е. закроетсоединение).
Что касается IoC / DI, я лично использую Castle Windsor .Вы можете внедрить объекты зависимостей как свойства или параметры построения.Регистрация контейнера Inversion of Control в качестве менеджера ресурсов зависимостей позволит вам (помимо прочего) возвращать тот же объект при запросе типа ресурса.По сути, для каждого класса вызывающего, который должен использовать MySqlHelper
, вы можете внедрить один и тот же экземпляр, когда создается экземпляр класса вызывающего или когда класс вызывающего ссылается на свое открытое свойство MySqlHelper
.Я лично предпочитаю инжекцию конструктора всякий раз, когда это возможно.Кроме того, когда я говорю «впрыскивать», я имею в виду, что вам не нужно беспокоиться об установке значения свойства, поскольку ваш IoC / DI делает это за вас (если он настроен правильно).См. здесь для более подробного объяснения.
В качестве еще одного примечания, подход IoC / DI действительно вступил бы в игру, только если ваш класс нестатичен, так что каждое приложение может иметь своесобственный экземпляр синглтона.Если MySqlHelper
является статическим, то вы можете поддерживать только одну строку подключения, если вы не передадите ее, что в исходном вопросе вы бы предпочли не делать.IoC / DI позволит вам использовать ваш элемент свойства MySqlHelper
, как если бы он был статическим, поскольку зарегистрированный контейнер будет гарантировать, что свойство имеет правильный экземпляр.