Открытие и закрытие SQLConnections в C # - PullRequest
0 голосов
/ 15 октября 2018

может кто-нибудь сказать мне, как правильно использовать SQL-соединение в C #?

Сейчас я делаю это так:

//some Code here
using (var sqlConnection = DatabaseUtil.DatabaseUtil.CreateSqlConnection(connectionString)) 
{
    var cmd = new SqlCommand();

    DatabaseUtil.DatabaseUtil.InitializeSqlCommand(ref cmd, query, sqlConnection);

    sqlConnection.Open();

    using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
    {
        reader.Read();

        if (reader.HasRows)
        {
            //some code here
        }

        reader.Close();
        reader.Dispose();
    }

    sqlConnection.Close();
}

DatabaseUtil записано в VB.NET .Здесь функция CreateSqlConnection:

Public Function CreateSqlConnection(connectionString As String) As SqlConnection
    Dim result As SqlConnection
    result = New SqlConnection(connectionString)
    Return result
End Function

И здесь вы можете увидеть функцию InitializeSqlCommand:

Public Sub InitializeSqlCommand(ByRef cmd As SqlCommand, query As String, sqlConnection As SqlConnection)
    cmd.CommandText = query
    cmd.CommandType = CommandType.Text
    cmd.Connection = sqlConnection
End Sub

Я делаю это правильно ?Или у вас есть предложения для улучшения для меня?

Буду признателен за каждый совет.

Али

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

вам не нужно DatabaseUtil.просто сделайте это так:

using (var sqlConnection =new SqlConnection(connectionString)){
   var cmd = new SqlCommand(query, sqlConnection);
   sqlConnection.Open();
   var reader = cmd.ExecuteReader();
   while(reader.Read())
    {
         //do whatever you want
    };
}

Вам не нужно закрывать соединение, когда вы используете using.

0 голосов
/ 15 октября 2018

Мне нужно начать с того, что в исходном посте ничего не говорится о неправильно , по сути, и вы можете продолжать использовать этот код просто отлично.

Но ... мы можемвсе еще лучше.

Нет необходимости передавать аргумент SqlCommand в InitializeSqlCommand() по ссылке.ИМО это ошибка в коде VB.ByVal здесь достаточно хорош, и ByRef предоставляет объект вашей команды вещам, которые вам могут не понадобиться.

В функции CreateSqlConnection() я склонен полагать, что если вы создаете соединение, вы 'скоро тоже захочу открыть.Плюс, мы можем немного сократить метод.

Я также стремлюсь либо поместить строки подключения непосредственно в мои эквивалентные модули DatabaseUtil, либо собрать модуль, чтобы он мог загрузить строку из файла конфигурации.Я не хочу каждый раз передавать эти данные в метод CreateSqlConnection().Сложите эти два абзаца так:

Private ReadOnly Property ConnectionString As String
    Get
         Return "connection string here"
    End Get
End Property

Public Function CreateSqlConnection() As SqlConnection
    Dim result As New SqlConnection(ConnectionString)
    result.Open()
    Return result
End Function

Это небольшая вещь, но SqlCommand также реализует IDisposble, поэтому в идеале он также будет в блоке using.На самом деле, в существующем методе InitializeSqlCommand() нет ничего, что вы не можете выполнить напрямую с помощью конструктора SqlCommand, так как CommandType.Text уже используется по умолчанию.Идем дальше и импортируем пространство имен DatabaseUtil, и вы можете соединить эти два абзаца следующим образом:

using (var sqlConnection = DatabaseUtil.CreateSqlConnection())
using (var cmd = new SqlCommand(query, sqlConnection))
{

Я также беспокоюсь о командной функции InitializeSqlCommand(), которая принимает строку query, но делаетнет обеспечения для параметров запроса.Да, вы все равно можете добавить параметры позже в коде, но по моему опыту это имеет тенденцию поощрять использование конкатенации строк для данных параметров ... или, точнее, не может адекватно препятствовать этому, что равносильно тому же.Вы хотите убедиться, что в приложении нет уязвимостей SQL-инъекций.Если вы продолжаете использовать InitializeSqlCommand(), я структурирую его так:

Public Function InitializeSqlCommand(cn As SqlConnection, query As String, ParamArray paramters() As SqlParamter) As SqlCommand
    Dim result As SqlCommand = cn.CreateCommand()
    result.CommandText = query
    If parameters IsNot Nothing AndAlso parameter.Length > 0 Then
       result.Parameters.AddRange(parameters)
    End If
    Return result
End Sub

Нет необходимости вызывать sqlConnection.Close(), если соединение было создано в блоке using.То же относится и к DataReader.

Наконец, типичный шаблон для DataReader - , а не для проверки свойства HasRows.Обычно достаточно только проверить результаты метода Read() и, как правило, в цикле while.

Собрать все вместе, включая пересмотренные функции VB, например:

var parameters = new SqlParameter[] { }; //define parameters here
using (var sqlConnection = DatabaseUtil.CreateSqlConnection())
using (var cmd = DatabaseUtil.InitializeSqlCommand(sqlConnection, query, parameters))
using (var reader = cmd.ExecuteReader())
{
    while(reader.Read())
    {
        //some code here
    }
}
0 голосов
/ 15 октября 2018

Я сомневаюсь, если вы хотите DatabaseUtil здесь;явное создание с помощью new сделает:

  // If you don't want to hardcode connection's type - SqlConnection -
  // (possible purpose of DatabaseUtil class) use dependency injection
  using (var sqlConnection = new SqlConnection(connectionString)) {
    sqlConnection.Open();

    // sqlConnection.CreateCommand() - we can avoid dependency 
    // and don't hardcode SqlCommand as "new SqlCommand"
    //DONE: wrap IDisposable into using, do not close it explicitly
    using (var cmd = sqlConnection.CreateCommand()) {
      cmd.CommandText = query;

      //TODO: you may want to provide Parameters here

      //DONE: wrap IDisposable into using, do not close it explicitly
      using (var reader = cmd.ExecuteReader()) {
        // reader.Read() returns true if record is read 
        // (i.e. we have at least one record)
        if (reader.Read()) {
          // We have at least one row
          // some code here
        } 
      }  
    } 
  }

Если вы хотите прочитать несколько записей , а не просто факт, что запрос возвращает хотя бы одну запись, превратите if (reader.Read()) в while:

      ... 
      //DONE: wrap IDisposable into using, do not close it explicitly
      using (var reader = cmd.ExecuteReader()) {
        // reader.Read() returns true if record is read 
        while (reader.Read()) {
          // record has been read
          // some code here 
        } 
      }  
      ...
...