为空时创建新 SqlConnection 的最佳方法

Best way to create new SqlConnection when is null

我有两种连接数据库的方法,我尽量避免双重代码 我的方法之一是可以 运行 alon(打开 SqlConnection 并关闭它)

使用现有 SqlConnection 并使用 SqlTransaction 的另一种方法(我不想打开另一个连接,也不想关闭它)

我的第一个方法:

public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject)
        {
            List<CSerieses> CSerieses = new List<CSerieses>();
            try
            {
                using (SqlConnection openCon = new SqlConnection(connectionString))
                {
                    string query = "SELECT [CSeriesNum],[CCount],[Mark] from [Serieses] " +
                            "where [TestPrimary]=@deliveryNumber";
                    SqlCommand command = new SqlCommand(query, openCon);
                    command.Parameters.AddWithValue("@deliveryNumber", DeliveryReportObject.DeliveryNumber);
                    openCon.Open();
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            CSerieses.Add(new CSerieses(reader.GetString(0), reader.GetInt32(1), reader.GetBoolean(2)));
                        }
                    }
                    openCon.Close();
                }
            }
            catch (Exception ex)
            {
                LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
            }
            return CSerieses;
        }

交易中使用的方法:

 public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject,
            SqlConnection co,SqlTransaction tran)
        {
            List<CSerieses> CSerieses = new List<CSerieses>();
            try
            {
                using (co)
                {
                    string query = "SELECT [CSeriesNum],[CCount],[Mark] from [Serieses] " +
                            "where [TestPrimary]=@deliveryNumber";
                    SqlCommand command = new SqlCommand(query, co, tran);
                    command.Parameters.AddWithValue("@deliveryNumber", DeliveryReportObject.DeliveryNumber);
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            CSerieses.Add(new CSerieses(reader.GetString(0), reader.GetInt32(1), reader.GetBoolean(2)));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
            }
            return CSerieses;
        }

我试着把它们结合起来:

public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject,
            SqlConnection co = null,SqlTransaction tran = null)
        {
            List<CSerieses> CSerieses = new List<CSerieses>();
            try
            {
                using (co ?? new SqlConnection(connectionString))
                {
                    if (co.IsOpened() == false)
                    {
                        co.Open();
                    }
                    string query = "SELECT [CSeriesNum],[CCount],[Mark] from [Serieses] " +
                            "where [TestPrimary]=@deliveryNumber";
                    SqlCommand command = new SqlCommand(query, co, tran);

                    if(tran != null)
                    {
                        command.Transaction = tran;
                    }

                    command.Parameters.AddWithValue("@deliveryNumber", DeliveryReportObject.DeliveryNumber);
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            CSerieses.Add(new CSerieses(reader.GetString(0), reader.GetInt32(1), reader.GetBoolean(2)));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
            }
            return CSerieses;
        }

它对我不起作用。我不知道如何检查它在 using 中是否为空,如果是,则创建一个新的 SqlConnection 实例,该实例应在 using 语句结束时关闭 而且我还是以正确的方式做到了?

这是一个主要问题:

using (co ?? new SqlConnection(connectionString))

如果传入 co,则 您不拥有它 - 调用者拥有 - 所以:您不应该处置它。我在这里建议的是:

bool ownConnection = false;
try
{
    if (co is null)
    {
        ownConnection = true;
        co = new SqlConnection(...);
        co.Open();
    }
    // your code here
}
finally
{
    if (ownConnection)
    {
        co?.Dispose();
    }
}

或者将其包装在一个助手中——也许是一个接受连接和连接字符串的自定义一次性对象:

public readonly struct ConnectionWrapper : IDisposable
{
    private readonly bool owned;
    public SqlConnection Connection { get; }
    public ConnectionWrapper(SqlConnection connection, string connectionString)
    {
        if (connection is null)
        {
            owned = true;
            Connection = new SqlConnection(connectionString);
            Connection.Open();
        }
        else
        {
            owned = false;
            Connection = connection;
        }
    }

    public void Dispose()
    {
        if (owned)
        {
            Connection?.Dispose();
        }
    }
}

那么你可以使用:

using var wrapped = new ConnectionWrapper(co, connectionString);
// your code, using wrapped.Connection

这似乎是一种非常符合超载概念的情况。
GetCSerieses 方法应该有两个版本,第一个构建自己的连接和事务,第二个同时采用非可选连接和非可选事务。第一个,在创建连接和事务后调用第二个。

现在,如果第三个方法需要调用,GetCSerieses 可以传递自己的连接和事务,而没有它们的调用将由第一个重载处理

public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject)
{
     using(SqlConnection con = new SqlConnection(......))
     {
        try
        {
            con.Open();


            using(SqlTransaction tran = con.BeginTransaction())
            {
                return GetCSerieses(DeliveryReportObject, con, tran);
            }

             // Or, if you don't need a transaction you could call the
             // overload passing null
             // return GetCSerieses(DeliveryReportObject, con, null);
         }
         catch(Exception ex)
         {
              LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
              return null; // ?? or  return new List<CSerieses>();
         }
     }
 }

 public static List<CSerieses> GetCSerieses(DeliveryReportObject DeliveryReportObject, SqlConnection co, SqlTransaction tran)
 {
        List<CSerieses> CSerieses = new List<CSerieses>();
        try
        {

             // We don't own the connection and the transaction object.
             // Whoever passed them to us is responsible of their disposal.

             string query = "......";
             SqlCommand command = new SqlCommand(query, co, tran);
             command.Transaction = tran;
             ....
        }
        catch (Exception ex)
        {
            LocalPulserDBManagerInstance.WriteLog(ex.StackTrace, ex.Message);
        }
        return CSerieses;
    }