Вопрос

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

Это было полезно?

Решение

Лично мне нравится использовать узко ограниченные соединения; откройте их поздно, используйте их и закройте (в блоке «using», все в локальном методе). В большинстве случаев пул соединений будет иметь дело с повторным использованием соединения, поэтому в этом подходе нет никаких дополнительных затрат.

Главное преимущество в передаче соединений раньше заключалось в том, чтобы вы могли передавать транзакцию; однако TransactionScope представляет собой более простой способ обмена транзакциями между методами .

Поскольку классы зависят от реализации, я бы написал каждый для открытия своей собственной собственной транзакции. В противном случае вы можете использовать фабричные методы ado.net для создания соответствующего типа из файла конфигурации (имя провайдера).

Другие советы

Лично мне нравится хранить стек моего текущего открытого соединения и транзакций поверх Локальное хранилище потоков с использованием SetData и GetData. Я определяю класс, который управляет моими соединениями с базой данных и позволяет ему использовать шаблон dispose. Это избавляет меня от необходимости передавать соединения и транзакции, что, как мне кажется, мешает и усложняет код.

Я бы настоятельно рекомендовал против оставить методы открытия соединений каждый раз, когда им нужны данные. Это приведет к действительно плохой ситуации, когда сложно управлять транзакциями во всем приложении, и слишком много соединений открываются и закрываются (я знаю о пуле соединений, поиск соединения из пула по-прежнему обходится дороже, чем повторно использовать объект)

Так что в итоге я получил что-то вроде этого (полностью не проверено):

class DatabaseContext : IDisposable {

    List<DatabaseContext> currentContexts;
    SqlConnection connection;
    bool first = false; 

    DatabaseContext (List<DatabaseContext> contexts)
    {
        currentContexts = contexts;
        if (contexts.Count == 0)
        {
            connection = new SqlConnection(); // fill in info 
            connection.Open();
            first = true;
        }
        else
        {
            connection = contexts.First().connection;
        }

        contexts.Add(this);
    }

   static List<DatabaseContext> DatabaseContexts {
        get
        {
            var contexts = CallContext.GetData("contexts") as List<DatabaseContext>;
            if (contexts == null)
            {
                contexts = new List<DatabaseContext>();
                CallContext.SetData("contexts", contexts);
            }
            return contexts;
        }
    }

    public static DatabaseContext GetOpenConnection() 
    {
        return new DatabaseContext(DatabaseContexts);
    }


    public SqlCommand CreateCommand(string sql)
    {
        var cmd = new SqlCommand(sql);
        cmd.Connection = connection;
        return cmd;
    }

    public void Dispose()
    {
        if (first)
        {
            connection.Close();
        }
        currentContexts.Remove(this);
    }
}



void Test()
{
    // connection is opened here
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 1"))
        {
            cmd.ExecuteNonQuery(); 
        }

        Test2(); 
    }
    // closed after dispose
}

void Test2()
{
    // reuse existing connection 
    using (var ctx = DatabaseContext.GetOpenConnection())
    {
        using (var cmd = ctx.CreateCommand("select 2"))
        {
            cmd.ExecuteNonQuery();
        }
    }
    // leaves connection open
}

Для целей автоматического тестирования его обычно легче передать. Это называется внедрение зависимостей .

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

Я лично работаю, чтобы максимально централизовать доступ к данным, однако, если это невозможно, я ВСЕГДА открываю новое соединение в других классах, так как я обнаружил, что при передаче слишком много других препятствий. фактический объект подключения.

Вот немного больше понимания этой проблемы. У меня есть класс, который управляет соединениями БД, и у меня есть 2 класса, которые реализуют интерфейс. Один из классов предназначен для SQL, а другой - для OLAP. Менеджер - это тот, кто знает, какое соединение использовать, поэтому он может передать точное соединение типу или тип может создать свое собственное соединение.

Вы можете передавать объекты соединения без каких-либо проблем (например, Microsoft Enterprise Library позволяет передавать вызовы статических методов в соединении), или вы можете управлять им внешне в соответствии с вашим дизайном, прямых технических компромиссов нет.

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

Установка соединения является потенциально дорогостоящей и потенциально добавляет туда и обратно. Итак, опять же, потенциально, лучший дизайн - передать объект подключения.

Я говорю потенциально, потому что, если вы являетесь приложением Microsoft ADO, вы, вероятно, используете пул соединений ....

Я бы посоветовал вам различать объект соединения и его состояние (открыто, закрыто).

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

Вызывайте этот метод, когда вам нужно открыть соединение. В самый последний момент, после настройки всех свойств SqlCommand, откройте соединение, используйте его, а затем закройте. В C # вы можете использовать оператор using, чтобы убедиться, что соединение закрыто. Если нет, обязательно закройте соединение в блоке finally.

Я бы использовал web.config

<configuration>
    <connectionStrings>
        <add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" />
        <add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" />
    </connectionStrings>
</configuration>

Затем вы можете ссылаться на него из любого места в приложении

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top