Используя вопрос об операторе

У меня есть два вопроса.

1) Необходимо ли всегда использовать оператор использования на соединении? Так, я использовал бы его на соединении и затем другом на читателе в рамках соединения? Таким образом, я использовал бы два оператора использования.

2) Позволяет говорят, что Вы используете оператор использования на соединении и также читателе, возвращаемом на соединении. Таким образом, у Вас есть два оператора использования. Это создает две Попытки {} Наконец {} блоки или всего один?

Спасибо!

5
задан Dan H 3 April 2010 в 16:10
поделиться

6 ответов

  1. Вы всегда должны использовать оператор using , когда объект реализует IDisposable . Это включает в себя соединения.

  2. Будет создано два вложенных блока try {} finally {} .

4
ответ дан 18 December 2019 в 08:27
поделиться

Будьте осторожны здесь. Вы должны всегда иметь оператор using для любого локального объекта, который реализует IDisposable. Это включает не только связи и читателей, но и команду. Но иногда это может быть сложно, именно где используется инструкция using. Если вы не будете осторожны, это может вызвать проблемы. Например, в коде, который следует за оператором using, программа чтения закроет еще до того, как вы сможете его использовать:

DataReader MyQuery()
{
    string sql="some query";
    using (var cn = new SqlConnection("connection string"))
    using (var cmd = new SqlCommand(sql, cn))
    {
        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            return rdr;
        }
    }
}

Вместо этого у вас есть четыре варианта. Один из них - дождаться создания блока using, пока вы не вызовете функцию:

DataReader MyQuery()
{
    string sql="some query";
    using (var cn = new SqlConnection("connection string"))
    using (var cmd = new SqlCommand(sql, cn))
    {
        cn.Open();
        return cmd.ExecuteReader();
    }
}

using (var rdr = MyQuery())
{
    while (rdr.Read())
    {
        //...
    }
}

Конечно, вы все равно должны быть осторожны с вашим соединением там, и это означает, что не забудьте написать блок using везде, где вы используете функцию.

Второй вариант - просто обрабатывать результаты запроса в самом методе, но это нарушает отделение уровня данных от остальной части программы.Третий вариант заключается в том, что ваша функция MyQuery () принимает аргумент типа Action, который вы можете вызывать внутри цикла while (rdr.Read ()), но это просто неудобно.

Обычно я предпочитаю четвертый вариант: превратить средство чтения данных в IEnumerable, например:

IEnumerable<IDataRecord> MyQuery()
{
    string sql="some query";
    using (var cn = new SqlConnection("connection string"))
    using (var cmd = new SqlCommand(sql, cn))
    {
        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
              yield return rdr;
        }
    }
}

Теперь все будет правильно закрыто, а код, который его обрабатывает, находится в одном месте. Вы также получаете приятный бонус: результаты вашего запроса будут хорошо работать с любым из операторов linq.

Наконец, кое-что новое, с чем я играю в следующий раз, когда я смогу создать полностью новый проект, который объединяет IEnumerable с передачей аргумента делегата:

//part of the data layer
private static IEnumerable<IDataRecord> Retrieve(string sql, Action<SqlParameterCollection> addParameters)
{
    //DL.ConnectionString is a private static property in the data layer
    // depending on the project needs, it can be implementing to read from a config file or elsewhere
    using (var cn = new SqlConnection(DL.ConnectionString))
    using (var cmd = new SqlCommand(sql, cn))
    {
        addParameters(cmd.Parameters);

        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
              yield return rdr;
        }
    }
}

А затем я использую его на уровне данных, например это:

public IEnumerable<IDataRecord> GetFooChildrenByParentID(int ParentID)
{
    //I could easily use a stored procedure name instead, and provide overloads for commandtypes.
    return Retrieve(
        "SELECT c.* 
         FROM [ParentTable] p 
         INNER JOIN [ChildTable] c ON c.ParentID = f.ID 
         WHERE f.ID= @ParentID", p => 
       {
          p.Add("@ParentID", SqlDbType.Int).Value = ParentID;
       }
     );
}
7
ответ дан 18 December 2019 в 08:27
поделиться

1) Следует ли всегда использовать оператор using в соединении? Итак, я бы использовал его для соединения, а затем еще один на считывателе в соединении ? Поэтому я бы использовал два оператора using .

Да, потому что они реализуют IDisposable . И не забудьте также использовать оператор using в команде:

using (DbConnection connection = GetConnection())
using (DbCommand command = connection.CreateCommand())
{
    command.CommandText = "SELECT FOO, BAR FROM BAZ";
    connection.Open();
    using (DbDataReader reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            ....
        }
    }
}

2) Допустим, вы используете оператор using в соединении, а также возвращаемый читатель на соединении . Итак, у вас есть два оператора using . Создает ли он два блока Try {} finally {} или только один?

Каждый using оператор создает свой собственный блок try / finally

{ {1}}
5
ответ дан 18 December 2019 в 08:27
поделиться

Возможно, эта статья будет вам интересна: Как реализовать IDisposable и Finalizers: 3 простых правила

0
ответ дан 18 December 2019 в 08:27
поделиться

Чтобы ответить каждому:

1) Да, лучше всего избавиться от обоих как можно скорее.

2) using () создаст два блока, обернутых друг в друга в одном и том же порядке. Сначала он удалит внутренний объект (считыватель), а затем удалит объект из внешнего, используя (соединение).

1
ответ дан 18 December 2019 в 08:27
поделиться

Особый пункт по 1). Вам нужно специально избегать этого метода, когда соединение используется в асинхронных методах ADO.NET - например, BeginExecuteReader, потому что, скорее всего, вы выпадете из области видимости и попытаетесь избавиться от соединение, пока выполняется асинхронная операция. Это похоже на случай, когда вы используете переменные класса, а не локальные переменные. Часто ссылка на соединение сохраняется в классе, используемом как «блок управления» для асинхронной операции.

2
ответ дан 18 December 2019 в 08:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: