Обычно я не рекомендую совместно использовать один экземпляр SqlConnection для нескольких запросов. Даже если вы включите MARS, вы могут столкнуться с проблемами производительности. Я думаю, что когда ваше соединение получает команду без чтения, буфер соединения приостановит все текущие чтения до завершения записи. Единственное, что вы действительно экономите, — это время, необходимое для установления соединения.
SqlConnections объединены, поэтому вы можете настроить провайдер должен иметь минимальное / максимальное количество экземпляров, доступных для запроса клиентов. Имейте в виду, что это также контролируется любой базой данных, к которой вы подключаетесь; предполагая, что вы подключаетесь к экземпляру 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 для предоставления строки подключения с учетом вашего запроса.
ИЗМЕНИТЬ
Yield позволяет вызывающей стороне использовать возвращенный объект до того, как контекст выполнения вернется к методу, дающему возврат для продолжения выполнения. Итак, в приведенном выше примере вызывающий объект может сделать что-то вроде этого:
// 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 действительно будет работать только в том случае, если ваш класс нестатичен, так что каждое приложение может иметь свой собственный экземпляр singleton. Если MySqlHelper
является статическим, вы можете поддерживать только одну строку подключения, если не передадите ее, что в исходном вопросе вы предпочли бы не делать этого. IoC/DI позволит вам использовать член свойства MySqlHelper
, как если бы он был статическим, поскольку зарегистрированный контейнер гарантирует, что свойство имеет правильный экземпляр.
person
bitxwise
schedule
27.05.2011