Как правильно вызывать несколько «SQL DataReader» в C #?

1

Я вызываю 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(); ? Каков правильный способ распределения ресурсов и устранения ошибок?

Кстати, он работает так, как есть. Заранее спасибо.

  • 0
    не забудьте использовать using
  • 0
    Если возможно, объедините два запроса в один, и, если он все еще производит два набора результатов, используйте NextResult для обработки обоих.
Показать ещё 3 комментария
Теги:
database
linq

7 ответов

4
Лучший ответ

Как упоминалось в моем комментарии - если возможно, объедините два запроса в один, а затем (если он все еще производит несколько наборов результатов), используйте 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
      }
     }
    }
  }
 }
}
  • 1
    +1 За то, что надоело писать это, даже с воровством ;-) Я связал ваш ответ от моего для полноты.
  • 1
    @AdamHouldsworth - И я тоже твой +1 (я бы не стал воровать без этого и прямо в ответе)
Показать ещё 2 комментария
4

Вот как я бы написал все это:

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 ;-)

  • 0
    Важно отметить, что он не может использовать второй DataReader из первого. Поэтому, если ему это нужно, было бы неплохо сначала заполнить List<T> которому он может получить доступ из второго цикла.
  • 0
    @TimSchmelter О, я вижу, на случай, если он намеревается получить материал от предыдущего читателя во втором цикле или что-то еще? Да, не заметил этого.
1

Правильный способ состоит в том, чтобы обернуть 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 фактически не закрывает соединение, поскольку установка соединения очень дорога. Он просто вернет соединение в пул соединений и позволит другим командам/читателям использовать его.

1

Для управления ресурсом вы можете использовать, 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 также с использованием блока кода.

0

Не забывайте свои высказывания о попытке уловить хотя :)

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();
}
  }
 }
}
0

Используйте "использование", вам не нужно вручную закрывать и удалять.

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();
}
  • 0
    Не забудьте также использовать using на SqlCommand .
  • 0
    Не отвечает на вопрос , который: «Что такое правильный способ вызова мультипликатор«DataReaders SQL?».
0

Открывайте новое соединение каждый раз, когда вам это нужно, это лучшие практики. ADO.net использует пул соединений для подключения к сеансу. http://msdn.microsoft.com/it-it/library/8xx3tyca(v=vs.110).aspx

Ещё вопросы

Сообщество Overcoder
Наверх
Меню