Я вызываю ExecuteReader();
для получения данных, тогда мне нужно получить другие данные с другим запросом. Моя структура всегда была такой:
class SomeClass
{
public static void Main(String[] args)
{
SqlConnection sqlConn = new SqlConnection();
sqlConn.ConnectionString = "some connection string"
SqlCommand SQLCmd = new SqlCommand();
SQLCmd.CommandText = "some query";
SQLCmd.Connection = sqlConn;
sqlConn.Open();
sqlReader = SQLCmd.ExecuteReader();
while (sqlReader.Read())
{
//some stuff here
}
sqlReader.Dispose();
sqlReader.Close();
sqlConn.Close();
SQLCmd.CommandText = "another query";
sqlConn.Open();
sqlReader = SQLCmd.ExecuteReader();
while (sqlReader.Read())
{
//some other stuff here
}
sqlReader.Dispose();
sqlReader.Close();
sqlConn.Close();
}
}
Они имеют одну и ту же строку соединения. Что еще они могут разделить? Могут ли они использовать один и sqlConn.Open();
же sqlConn.Open();
? Каков правильный способ распределения ресурсов и устранения ошибок?
Кстати, он работает так, как есть. Заранее спасибо.
Как упоминалось в моем комментарии - если возможно, объедините два запроса в один, а затем (если он все еще производит несколько наборов результатов), используйте NextResult
для NextResult
.
Кража структуры Адама, но с тем изменением:
class SomeClass
{
public static void Main(String[] args)
{
using (SqlConnection sqlConn = new SqlConnection("some connection string"))
{
sqlConn.Open();
using (SqlCommand comm = new SqlCommand("some query; some other query;", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
if(sqlReader.NextResult())
{
while (sqlReader.Read())
{
//some other stuff here
}
}
}
}
}
}
Вот как я бы написал все это:
class SomeClass
{
public static void Main(String[] args)
{
using (SqlConnection sqlConn = new SqlConnection("some connection string"))
{
sqlConn.Open();
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some other stuff here
}
}
}
}
}
Оператор using
обрабатывает удаление элементов, когда блок завершен. Что касается совместного использования, вы можете оставить соединение открытым по командам.
Самое главное, чтобы избавиться от всего этого было бы связью, но я склонен к соблюдению оператора using
если элемент IDisposable
независимо от того, что он на самом деле делает в фоновом режиме (который может изменяться по мере его реализации),
Не забывайте, что также есть несколько наборов активных результатов (как показано в этом ответе) из одной команды и одного считывателя, где вы переходите читателя к следующему набору результатов.
return connection.Query<T>(procedureName, param, commandType: CommandType.StoredProcedure);
Использование Dapper ;-)
DataReader
из первого. Поэтому, если ему это нужно, было бы неплохо сначала заполнить List<T>
которому он может получить доступ из второго цикла.
Правильный способ состоит в том, чтобы обернуть SqlConnection
и SqlCommand
с using
-statements. Это заставит Dispose
вызываться для объектов, когда остается блок использования, даже если выбрано исключение. (Это не относится к вашему текущему коду.)
Что-то в строке
using(var cnn = new SqlConnection("connectionstring")){
cnn.Open();
using(var cmd = new SqlCommand("SELECT 1")){
var reader = cmd.ExecuteReader();
while(reader.Read()) { /* doStuff */ }
}
}
Независимо от подхода Close
/Dispose
фактически не закрывает соединение, поскольку установка соединения очень дорога. Он просто вернет соединение в пул соединений и позволит другим командам/читателям использовать его.
Для управления ресурсом вы можете использовать, using
, как показано, как под...
SQLCmd.CommandText = "some query";
SQLCmd.Connection = sqlConn;
sqlConn.Open();
//using will dispose reader automatically.
using(sqlReader = SQLCmd.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
//sqlReader.Dispose();
//sqlReader.Close();
//sqlConn.Close();
SQLCmd.CommandText = "another query";
//no need to open connection again.
// sqlConn.Open();
// sqlReader = SQLCmd.ExecuteReader();
using(sqlReader = SQLCmd.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
//sqlReader.Dispose();
//sqlReader.Close();
//sqlConn.Close();
вы можете использовать, using
только для тех классов, в которых реализуются IDispose
интерфейс. в вашем примере вы можете использовать SqlConnection
и SqlCommand
также с использованием блока кода.
Не забывайте свои высказывания о попытке уловить хотя :)
class SomeClass
{
public static void Main(String[] args)
{
using (SqlConnection sqlConn = new SqlConnection("some connection string"))
{
try{
sqlConn.Open();
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some other stuff here
}
}
}
catch()
{
// Do exception catching here or rollbacktransaction if your using begin transact
}
finally
{
sqlConn.Close();
}
}
}
}
Используйте "использование", вам не нужно вручную закрывать и удалять.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand("spTest", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("@employeeid", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
using
на SqlCommand
.
Открывайте новое соединение каждый раз, когда вам это нужно, это лучшие практики. ADO.net использует пул соединений для подключения к сеансу. http://msdn.microsoft.com/it-it/library/8xx3tyca(v=vs.110).aspx
using
NextResult
для обработки обоих.