简体   繁体   中英

Best way to create new SqlConnection when is null

I have two methods that connect to the database and I try to avoid double code one of my methods is one that can run alon (open itself SqlConnection and close it)

another method using existing SqlConnection and using SqlTransaction also (I don't want to open another connection and also I don't want to close it)

my first method:

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

The method that using on the transaction:

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

I try to combine them:

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

It does not work for me. I have no idea how to check if it null in using and if yes to create a new instance of SqlConnection that should close at the end of the using statement And I do it the right way anyway?

This is a major problem:

using (co ?? new SqlConnection(connectionString))

If co is passed in, then you don't own it - the caller does - so: you shouldn't be disposing it. What I would suggest here is:

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

or wrap that up in a helper - perhaps a custom disposable that takes a connection and connection string:

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();
        }
    }
}

then you can just use:

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

This seems that kind of situation that perfectly fits the overload concept.
The GetCSerieses method should have two versions, the first one builds its own connection and transaction, the second one takes both a non optional connection and a non optional transaction. The first one, after creating the connection and the transaction calls the second one.

Now if a third method requires a call the GetCSerieses could pass its own connection and transaction, while a call without them will be handled by the first overload

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM