Лично мне нравится хранить стек моего текущего открытого соединения и транзакций поверх Thread Local Storage с использованием 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
}