C# 试图避免嵌套的SqlConnection

C# 试图避免嵌套的SqlConnection,c#,sqlconnection,C#,Sqlconnection,我不确定嵌套的SqlConnections是否可行,但我真的想远离它。我现在在代码中遇到了一个范围问题,我正试图找出解决方法 因此,直到最近,我还拥有一个全局SqlConnection,它在应用程序启动时打开,在应用程序完成时关闭。我现在发现了.NET连接池的概念,因此我更改了代码,使每个SqlCommand(或它们的组)使用自己的、新创建和打开的SqlConnection,信任.NET来管理连接池和伴随的开销 我现在遇到的问题是,我有几个代码块看起来像这样: using (SqlConnect

我不确定嵌套的
SqlConnections
是否可行,但我真的想远离它。我现在在代码中遇到了一个范围问题,我正试图找出解决方法

因此,直到最近,我还拥有一个全局
SqlConnection
,它在应用程序启动时打开,在应用程序完成时关闭。我现在发现了.NET连接池的概念,因此我更改了代码,使每个
SqlCommand
(或它们的组)使用自己的、新创建和打开的
SqlConnection
,信任.NET来管理连接池和伴随的开销

我现在遇到的问题是,我有几个代码块看起来像这样:

using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
{       
    sqlConnection.Open();
    using (SqlCommand sqlCommand1 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand1.ExecuteNonQuery();
    }
    using (SqlCommand sqlCommand2 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand2.ExecuteNonQuery();
    }
    .
    .
    .
    ClassGlobal.WriteAction(action);
}
public static void WriteAction(MyActionClass action)
{
    using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
    {       
        sqlConnection.Open();
        using (SqlCommand sqlCommand = new SqlCommand("Write the action to the DB", sqlConnection))
        {
            sqlCommand.ExecuteNonQuery();
        }
    }
}
public static void WriteAction(MyActionClass action)
{
    using (TransactionScope transactionScope = new TransactionScope())
    {
        using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
        {
            sqlConnection.Open();
            WriteAction(action, sqlConnection);
        }
        transactionScope.Complete();
    }
}
而ClassGlobal.WriteAction()函数的外观如下所示:

using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
{       
    sqlConnection.Open();
    using (SqlCommand sqlCommand1 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand1.ExecuteNonQuery();
    }
    using (SqlCommand sqlCommand2 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand2.ExecuteNonQuery();
    }
    .
    .
    .
    ClassGlobal.WriteAction(action);
}
public static void WriteAction(MyActionClass action)
{
    using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
    {       
        sqlConnection.Open();
        using (SqlCommand sqlCommand = new SqlCommand("Write the action to the DB", sqlConnection))
        {
            sqlCommand.ExecuteNonQuery();
        }
    }
}
public static void WriteAction(MyActionClass action)
{
    using (TransactionScope transactionScope = new TransactionScope())
    {
        using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
        {
            sqlConnection.Open();
            WriteAction(action, sqlConnection);
        }
        transactionScope.Complete();
    }
}
如您所见,在
WriteAction()
中创建了一个新的
SqlConnection
,它是从第一个
SqlConnection
的范围内调用的。不好的!我尽量避免这样

在过去,如果使用(SqlConnection)块时没有这些
,并且所有
SqlCommands
都指向同一个(全局)
SqlConnection
,这就不会有问题了。显然,我可以使用(SqlCommand)
将调用移动到
的右大括号下方的
WriteAction()
,但是:

  • 我传递给它的
    action
    实例经常在
    SqlConnection
    范围内实例化和填充,因此我必须进行更多更改(很多更改)以将它们移出
    SqlConnection
    范围。它们很多,而且会很毛茸茸的
  • 实际上,我更希望
    WriteAction()
    调用可以像上面的例子一样位于
    SqlConnection
    范围内,这样我就可以将它全部封装在
    TransactionScope
    中,这是迄今为止不可能实现的,但看起来确实是个好主意
  • 这就是我计划要做的,但是我想听听你们中的任何人是否认为这不是一个好的实践,或者你是否可以提出一个更好的方法。(我最近发现我的全局
    SqlConnection
    不是一个好的实践,它导致了大量的时间花在修复上。我希望以后避免这样的发现)

    我向
    WriteAction()
    函数添加一个参数,使其如下所示:

    public static void WriteAction(MyActionClass action, SqlConnection sqlConnection)
    {   
        using (SqlCommand sqlCommand = new SqlCommand("Write the action to the DB", sqlConnection))
        {
            sqlCommand.ExecuteNonQuery();
        }
    }
    
    这意味着,与其将对
    WriteAction()
    的调用移到
    SqlConnection
    范围之外,我可以简单地将
    SqlConnection
    作为参数添加到函数中,以便函数中的
    SQLCommand
    使用相同的连接,即使该连接已登记到
    TransactionScope

    对于从任何
    SqlConnection
    范围之外调用
    WriteAction()
    的少数实例,我可以编写如下重载函数:

    using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
    {       
        sqlConnection.Open();
        using (SqlCommand sqlCommand1 = new SqlCommand("SQL code here", sqlConnection))
        {
            sqlCommand1.ExecuteNonQuery();
        }
        using (SqlCommand sqlCommand2 = new SqlCommand("SQL code here", sqlConnection))
        {
            sqlCommand2.ExecuteNonQuery();
        }
        .
        .
        .
        ClassGlobal.WriteAction(action);
    }
    
    public static void WriteAction(MyActionClass action)
    {
        using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
        {       
            sqlConnection.Open();
            using (SqlCommand sqlCommand = new SqlCommand("Write the action to the DB", sqlConnection))
            {
                sqlCommand.ExecuteNonQuery();
            }
        }
    }
    
    public static void WriteAction(MyActionClass action)
    {
        using (TransactionScope transactionScope = new TransactionScope())
        {
            using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
            {
                sqlConnection.Open();
                WriteAction(action, sqlConnection);
            }
            transactionScope.Complete();
        }
    }
    

    这看起来是个好主意,还是我会在两年后后悔这个决定?

    SqlConnection
    实例传递给该方法是绝对正确的。但是,我不确定您是否使用了最后一种方法,没有
    SqlConnection
    的重载方法是个好主意。它隐藏了一个事实,即您应该更好地使用另一个新的重载。它会编译代码,从而阻止您修复现在应该修复的代码

    请注意,
    使用
    块不是问题,而是打开的连接。只要不打开连接,连接池就不需要打开物理连接

    因此,在调用
    WriteAction
    之前关闭连接也是一个可行的选择:

    using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
    {       
        sqlConnection.Open();
        using (SqlCommand sqlCommand1 = new SqlCommand("SQL code here", sqlConnection))
        {
            sqlCommand1.ExecuteNonQuery();
        }
        using (SqlCommand sqlCommand2 = new SqlCommand("SQL code here", sqlConnection))
        {
            sqlCommand2.ExecuteNonQuery();
        }
        // ...
        sqlConnection.Close();
    
        ClassGlobal.WriteAction(action);
    
        // ... perhaps open it again here
    }
    
    发件人:

    每当用户在连接上调用
    Open
    ,池处理程序都会查找 池中的可用连接。如果池连接可用, 它将其返回给调用方,而不是打开新连接。什么时候 应用程序在连接上调用
    Close
    ,池程序返回它 指向活动连接的池集,而不是关闭它。一旦 连接返回到池中,即可在上重用 下一个
    打开
    调用


    因此,您可以看到,只要不保持外部连接打开,在
    WriteAction
    中使用
    的嵌套
    就不是问题。不要将连接实例与物理连接混淆。

    在我看来很好。但是,将事务放在单个操作周围的重载看起来是错误的。我猜这只是说明而已。是的,当然。我的WriteAction()函数实际上不仅仅是一个SQL操作。谢谢,谢谢。这绝对是一个很好的建议。事实上,这是我第一次理解SqlConnection.Close()的用途。我一直在想,看到结尾的大括号也会做同样的事情。不过,在调用WriteAction()之后,我通常会有更多的SqlCommands。您是希望传递连接还是在调用WriteAction()后再次调用sqlCommand.Open()?@DewaldSwanepoel:没有更多的背景信息,这只是口味问题
    ClassGlobal.WriteAction
    听起来好像可以从任何地方调用它。如果调用方有
    SqlConnection
    ,那么期望调用方有一个
    SqlConnection就不好了。另一个问题是,这种没有上下文/类的全局方法是否是最佳实践。这违反了面向对象的原则。另一个问题是,您是否应该通过为每个步骤创建新方法或为所有步骤提供一个存储过程来重构外部使用的方法以减少工作量。