Используя утверждение вопроса - PullRequest
5 голосов
/ 03 апреля 2010

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

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

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

Спасибо!

Ответы [ 6 ]

7 голосов
/ 03 апреля 2010

Будь осторожен здесь. Вы должны всегда иметь оператор using для любого локального объекта, который реализует IDisposable. Это включает не только связи и читателей, но и команду. Но иногда это может быть хитро точно , где , что идет с использованием оператора. Если вы не будете осторожны, это может вызвать проблемы. Например, в коде, который следует за оператором 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;
       }
     );
}
5 голосов
/ 03 апреля 2010

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

Да, потому что они реализуют 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 создаст свой собственный try/finally блок

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

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

2 голосов
/ 03 апреля 2010

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

1 голос
/ 03 апреля 2010

Чтобы ответить на каждый вопрос:

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

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

0 голосов
/ 03 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...