[C#] передача объекта подключения DB к методам


Answers

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

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

Поэтому я получаю что-то в этом направлении (полностью непроверенный):

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
}
Question

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




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

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

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




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




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

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




Links