Следует ли повторно использовать объекты SqlConnection, SqlDataAdapter и SqlCommand?

Я работаю с объектом DAL, который написан в макете, аналогичном приведенному ниже коду. Я упростил код кода, чтобы показать настройку.

public class UserDatabase : IDisposable
{
    private SqlDataAdapter UserDbAdapter;
    private SqlCommand UserSelectCommand;
    private SqlCommand UserInsertCommand;
    private SqlCommand UserUpdateCommand;
    private SqlCommand UserDeleteCommand;

    private System.Data.SqlClient.SqlConnection SQLConnection; 

    public UserDatabase()
    {
        this.SQLConnection = new System.Data.SqlClient.SqlConnection(ConnectionString);
        this.UserDbAdapter= new SqlDataAdapter(); 
        this.UserDbAdapter.DeleteCommand = this.UserDeleteCommand;
        this.UserDbAdapter.InsertCommand = this.UserInsertCommand;
        this.UserDbAdapter.SelectCommand = this.UserSelectCommand;
        this.UserDbAdapter.UpdateCommand = this.UserUpdateCommand;
    }

    private bool FillUsers(DataSet UserDataSet, out int numberOfRecords)
    {
        bool success = true;

        numberOfRecords = 0;
        string errorMsg = null;

        this.UserDbAdapter.SelectCommand = this.GetUsersSelectCommand();

        numberOfRecords = UserDbAdapter.Fill(UserDataSet, UsersTableName);

        return success;
    }

    private SqlCommand GetUserSelectCommand()
    {
        if (this.UserSelectCommand==null)
            this.UserSelectCommand= new System.Data.SqlClient.SqlCommand();
        this.UserSelectCommand.CommandText = "dbo.Users_Select";
        this.UserSelectCommand.CommandType = System.Data.CommandType.StoredProcedure;
        this.UserSelectCommand.Connection = this.SQLConnection;
        this.UserSelectCommand.Parameters.Clear();
        this.UserSelectCommand.Parameters.AddRange(new System.Data.SqlClient.SqlParameter[] {
        new System.Data.SqlClient.SqlParameter("@RETURN_VALUE", System.Data.SqlDbType.Variant, 0, System.Data.ParameterDirection.ReturnValue, false, ((byte)(0)), ((byte)(0)), "", System.Data.DataRowVersion.Current, null)});

        return UserSelectCommand;
    }

Есть несколько других функций типа Fill, которые написаны таким же образом с повторным использованием объекта Connection, SqlCommands и SqlDataAdapter. SqlDataAdapter управляет открытием и закрытием SqlConnection изнутри.

Итак, мой вопрос состоит из нескольких частей. Это плохой дизайн? Если да, то почему?

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

    public bool FillUsers(DataSet UserDataSet)
    {
        using (SqlConnection conn = new SqlConnection(ConnectionString))
        {
            using (SqlCommand command = GetUsersSelectCommand())
            {
                using (SqlDataAdapter adapter = new SqlDataAdapter(command, conn))
                {
                    adapter.Fill(UserDataSet, UsersTableName);
                }
            }
        }
    }

Это должно быть сделано для всех функций, которые вроде создания, удаления, а затем переделки были бы хуже, чем хранение предметов. Однако, похоже, это та установка, которую я вижу повсюду в Интернете.


person Equixor    schedule 27.06.2012    source источник
comment
Вы измерили проблему производительности так, что чувствуете необходимость в оптимизации? Подключения к базе данных по дизайну объединены в пулы. Не нужно переваливать наверху.   -  person spender    schedule 28.06.2012
comment
Аналогичный вопрос я задал несколько лет назад: stackoverflow.com/questions/226127/   -  person spender    schedule 28.06.2012
comment
Нет связанных проблем с производительностью. Я начинаю новый проект, и мне нужен объект доступа к данным, и мне было любопытно, правильно ли это или есть лучший способ.   -  person Equixor    schedule 28.06.2012


Ответы (1)


Нет, в этом нет ничего плохого. Вы должны избавиться от ваших объектов, реализующих IDisposable, как только вы закончите с ними.

Если задано SqlConnection, когда вы удаляете соединение, базовое соединение просто будет возвращено в пул. Это не обязательно «закрыто», как вы могли подумать. Лучше всего позволить пулу подключений делать свою работу. Здесь есть ссылка на объединение подключений ADO.NET в MSDN. Попытки заставить его делать то, для чего он не предназначен (некоторые люди, как ни странно, называют это оптимизацией), обычно являются спекуляцией по кроличьей норе.

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

person Bryan Crosby    schedule 27.06.2012
comment
Верхний код не удаляет ни один из объектов, пока не будет удален объект UserDatabase. Получается, что их повторное использование будет противоречить этой дизайнерской практике? - person Equixor; 28.06.2012
comment
@Equixor: я имел в виду более конкретно SqlConnection. Имя вашего класса UserDatabase немного вводит в заблуждение, потому что это не настоящая база данных. Возможно, вы могли бы создать метод с именем GetUsers (), который возвращал бы список пользователей. Ваш второй кодовый пост является правильным. Удерживать их - хуже (и иногда это приводит к трудновоспроизводимым ошибкам) - person Bryan Crosby; 28.06.2012
comment
Хорошо спасибо. Я уверен, что общий дизайн этого тоже можно улучшить. Большинство имеющихся у нас классов DAL подобны этому и заполняют наборы данных, которые затем используются BLL. - person Equixor; 28.06.2012