Инкапсуляция и размещение объектов SqlClient в порядке - PullRequest
0 голосов
/ 26 сентября 2018

Я пытаюсь наложить свои вызовы клиентских объектов Sql так, чтобы они надежно удалялись.Примерно так:

Открыть соединение с базой данных -> Создать команду -> Читать результаты -> Закрыть команду -> Закрыть соединение с базой данных

Пока это удалось, когда я это сделалвсе эти вещи в одном методе.

Проблема в том, что это подвержено ошибкам.И беспорядок для чтения.

Когда я пытаюсь создать общий метод для обработки этого, который очищает все и возвращает читателя, соединение закрывается до того, как читатель запускается.

//closes connection before it can be read...apparently the reader doesn't actually have any data at that point ... relocating to disposable class that closes on dispose
public SqlDataReader RunQuery(SqlCommand command)
{
    SqlDataReader reader = null;
    using (var dbConnection = new SqlConnection(_dbConnectionString))
    {
        try
        {
            dbConnection.Open();

            command.Connection = dbConnection;

            reader = command.ExecuteReader();  // connection closed before data can be read by the calling method
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        finally
        {
            dbConnection.Close();
        }
    }

    return reader;
}

Я могу обойти это, создав собственный класс, который реализует IDispose (и т. Д.), Но затем, когда я обертываю его тем же оператором using, он занимает столько же строк, сколько соединение с базой данных с помощью оператора.

Как я могупозаботиться о соединении с базой данных в повторяющемся классе, который позаботится обо всех этих артефактах и ​​закроет соединение?

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

так нет ли способа создать повторно используемый метод, который убирает все / большинство вложенных операторов using?

Для возврата DataReader из метода поддерживается специальный шаблон, например:

static IDataReader GetData(string connectionString, string query)
{
    var con = new SqlConnection(connectionString);
    con.Open();
    var cmd = con.CreateCommand();
    cmd.CommandText = query;
    var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
    return rdr;
}

Затем вы можете вызвать этот метод в блоке using:

    using (var rdr = GetData(constr, sql))
    {
        while (rdr.Read())
        {
            //process rows
        }
    } // <- the DataReader _and_ the connection will be closed here
0 голосов
/ 26 сентября 2018

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

public List<object> RunQuery(SqlCommand command)
{
    List<object> results = new List<object>();
    using (var dbConnection = new SqlConnection(_dbConnectionString))
    {
        try
        {
            dbConnection.Open();

            command.Connection = dbConnection;
            using (SqlDataReader reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    // Repeat for however many columns you have
                    results.Add(reader.GetString(0));
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    return results;
}

Я не знаю структуру вашегоданные, но важным моментом является то, что вам нужно прочитать ваши данные (reader.GetString делает это), прежде чем избавиться от соединения.Вы можете найти больше информации о том, как правильно читать ваши данные здесь .

Редактировать: Как уже упоминалось, я удалил ваше заявление finally.Это потому, что ваше заявление using по сути делает то же самое.Вы можете рассматривать оператор using как блок try - finally.Ваш одноразовый предмет всегда будет утилизирован после завершения оператора using.

...