为空时创建新 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;
}
我有两种连接数据库的方法,我尽量避免双重代码 我的方法之一是可以 运行 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;
}