Идея использования SqlDataReader в качестве ресурса - PullRequest
3 голосов
/ 30 июня 2009

Исходя из этого вопроса, я снова и снова пишу следующий код:

SqlCommand command = new SqlCommand();
// Code to initialize command with what we want to do
using (SqlConnection connection = openConnection())
{
    command.Connection = connection;
    using (SqlDataReader dataReader = thisCommand.ExecuteReader())
    {
        while (dataReader.Read())
        {
            // Do stuff with results
        }
    }
}

Довольно утомительно вкладывать два оператора использования. Есть ли способ сообщить SqlDataReader, что он владеет командой, и сообщить команде, что он владеет соединением?

Если бы был способ сделать это, я мог бы написать вспомогательный метод, который можно было бы вызвать так:

// buildAndExecuteCommand opens the connection, initializes the command
// with the connection and returns the SqlDataReader object. Dispose of the
// SqlDataReader to dispose of all resources that were acquired
using(SqlDataReader reader = buildAndExecuteCommand(...))
{
    // Do stuff with reader
}

Или я должен прикусить пулю и написать свою собственную обертку поверх SqlDataReader?

Ответы [ 5 ]

7 голосов
/ 30 июня 2009

Одна вещь будет состоять в том, чтобы написать метод, который избавился бы от вас, вызывая делегат с каждым результатом. Например:

using (SqlConnection connection = openConnection())
{
    command.Connection = connection;
    ExecuteReaderWithCommand(command, reader =>
    {
        // Do stuff with the result here.
    });
}

Тогда ExecuteReaderWithCommand будет выглядеть примерно так:

public static void ExecuteReaderWithCommand(SqlCommand command,
    Action<SqlDataReader> action)
{
    using (SqlDataReader dataReader = thisCommand.ExecuteReader())
    {
        while (reader.Read())
        {
            action(reader);
        }
    }
}

Вы можете сделать это методом расширения на SqlCommand, если хотите. Черт возьми, вы можете пойти в город и открыть для вас соединение, если хотите ... чем больше вы можете абстрагироваться от идеи "открыть / использовать / закрыть", тем лучше.

1 голос
/ 30 июня 2009

Вы можете написать что-то вроде этого и сказать dataReader закрыть соединение после использования:

SqlCommand command = new SqlCommand();
command.Connection = openConnection();
using (SqlDataReader dataReader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
    while (dataReader.Read())
    {
        // Do stuff with results
    }
}

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

0 голосов
/ 30 июня 2009

Использование делегата, такого как Action , конечно, вариант, но я использовал набор перегрузок, аналогичный приведенному ниже начиная с .NET 1.0. Вызывающий использует блок using для удаления возвращенного считывателя, который, в свою очередь, удаляет соединение.

public IDataReader ExecuteReader(string commandText, CommandType commandType, 
                                      IDbDataParameter[] parameters)
{
    IDbConnection connection = CreateConnection();
    try
    {
        IDbCommand command = CreateCommand(commandText, connection);
        command.CommandType = commandType;
        AppendParameters(command, parameters);
        connection.Open();
        return command.ExecuteReader(CommandBehavior.CloseConnection);
    }
    catch
    {
        connection.Close();
        throw;
    }
}
0 голосов
/ 30 июня 2009

Почему бы не взглянуть на Enterprise Library DAAB ?

Вот пример кода из документации , скорректированный для вашего сценария:

Database db = DatabaseFactory.CreateDatabase();

using (IDataReader reader = db.ExecuteReader(CommandType.Text, "SQL here..." ))
{
   while (reader.Read())
    {
        action(reader);
    }
}
0 голосов
/ 30 июня 2009

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

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