[英]Am I closing this SQL connection in a C# function appropriately?
為了試圖解決有關保持打開狀態並超過最大池數的連接的問題 ,我試圖重寫用於連接數據庫的函數。
該函數存在於本地編譯的庫中。 使用反射器,我可以看到代碼如下:
public SqlProvider([Optional, DefaultParameterValue("")] string StrConnection)
{
string str;
if (StrConnection == "")
{
str = ConfigurationSettings.AppSettings["ConStr"];
}
else
{
str = StrConnection;
}
SqlConnection connection = new SqlConnection(str);
connection.Open();
this.MyCommand = new SqlCommand();
SqlCommand myCommand = this.MyCommand;
myCommand.Connection = connection;
myCommand.CommandType = CommandType.Text;
myCommand = null;
this.MyDataAdapter = new SqlDataAdapter(this.MyCommand);
this.MyCommandBuilder = new SqlCommandBuilder(this.MyDataAdapter);
this.MyDataSet = new DataSet();
}
我正計划對此進行閱讀
public SqlProvider([Optional, DefaultParameterValue("")] string StrConnection)
{
string str;
if (StrConnection == "")
{
str = ConfigurationSettings.AppSettings["ConStr"];
}
else
{
str = StrConnection;
}
using (SqlConnection connection = new SqlConnection(str))
{
connection.Open();
this.MyCommand = new SqlCommand();
SqlCommand myCommand = this.MyCommand;
myCommand.Connection = connection;
myCommand.CommandType = CommandType.Text;
myCommand = null;
this.MyDataAdapter = new SqlDataAdapter(this.MyCommand);
this.MyCommandBuilder = new SqlCommandBuilder(this.MyDataAdapter);
this.MyDataSet = new DataSet();
}
}
然后重新編譯dll。 假定通常在公共類的頂部創建SQLProvider()
的實例,然后在類成員中使用該實例(例如:
public class Banner
{
DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr);
public Banner()
{
}
public DataTable GetBannerImages(string bannerLocation,int DeptId)
{
using (DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr))
{
DataTable dt = new DataTable();
//Add Parameter @BannerLocation for Banner of Specific Location
//Call proc_getBannerImages Stored procedure for Banner Images
db.AddStoredProcParameter("@BannerLocation", SqlDbType.VarChar, ParameterDirection.Input, 100, bannerLocation);
db.AddStoredProcParameter("@DeptId", SqlDbType.Int, ParameterDirection.Input, 0, DeptId);
dt = db.ExecuteStoredProcedure("proc_getBannerImages");
return dt;
}
}
}
我要這樣做正確嗎? 在我看來,連接將在實際檢索數據之前被處理掉。 另外,Visual Studio告訴我SQLProvider()
必須隱式轉換為System.IDisposable
我將如何實現這一點?
我試過在using (DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr)){}
語句中包裝class Banner
所有成員,但是intellisense然后在類struct中顯示“ Invalid using (DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr)){}
” ,或接口成員聲明”錯誤。
最好的方法是什么?
更新我曾嘗試拆解調整和重新編譯DSLibrary,但是正如CHris_Lively所說,我認為它對我沒有任何幫助。 到目前為止,將有問題的實例更改為我認為是更標准的格式是可行的:
public DataTable GetBannerImages(string bannerLocation,int DeptId)
{
using (SqlConnection conn = new SqlConnection(Defaults.ConnStr))
{
SqlCommand cmd = new SqlCommand("proc_getBannerImages", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@BannerLocation", bannerLocation));
cmd.Parameters.Add(new SqlParameter("@DeptId", DeptId));
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = cmd;
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
}
我將要研究企業庫,看來這可能是前進的方向。
不建議將連接保留的時間不要超過要求的時間(另請參見“ 提高.NET應用程序的性能和可伸縮性: Microsoft Press的模式和實踐”的第14章)。
在實踐中,我將更改您的類,以使其不具有SqlConnection(或SqlDataAdapter
或SqlCommandBuilder
)作為類的成員(如果必須 ,則應實現IDisposable
模式),而是創建新實例,並使用using語句包裝關於需要使用它們的類方法。
我認為您的做法不正確。 一旦您到達using塊的末尾,SqlConnection變量將變得不可用。 如果要在構造函數外部使用它,請不要在SqlConnection變量周圍使用using {}(sqlcommand變量MyCommand在構造函數外部間接使用它)。
相反,讓您的SqlProvider類實現IDisposable,然后在其中的MyCommand,MyDataAdapter,MyDataSet等變量上調用Dispose。
您可能在SqlProvider類中應該有以下內容:
public void Dispose()
{
if (MyCommand != null)
{
MyCommand.Dispose();
}
//... Similarly for MyDataAdapter,MyDataSet etc.
}
如果要在using塊中使用它,您的類需要實現IDisposable接口。 有關dispose()和IDisposable的准則,請參見http://msdn.microsoft.com/zh-cn/library/system.idisposable.dispose%28v=VS.100%29.aspx 。
你近了 但是,有幾個問題。
首先,整個DSLibrary似乎根本沒有買任何東西。
進行數據訪問時,通常需要在獲取連接和執行命令具有相同功能的地方進行結構化。 您的方法只應返回操作結果。 這樣,您可以干凈地使用連接,命令和閱讀器的IDisposable接口。
以下示例使用企業庫 。 請注意,Db沒有using子句。 它沒有實現IDisposable。 相反,該命令在超出范圍時負責釋放連接:
public static DataTable GetBannerImages(String bannerLocation, Int32 departmentId)
{
DataTable result = new DataTable();
result.Locale = CultureInfo.CurrentCulture;
Database db = DatabaseFactory.CreateDatabase("NamedConnectionStringFromConfig");
using (DbCommand dbCommand = db.GetStoredProcCommand("proc_getBannerImages"))
{
db.AddInParameter(dbCommand, "BannerLocation", DbType.String, bannerLocation);
db.AddInParameter(dbCommand, "DeptId", DbType.Int32, departmentId);
using (IDataReader reader = db.ExecuteReader(dbCommand))
{
SopDataAdapter dta = new SopDataAdapter(); // descended from DbDataAdapter
dta.FillFromReader(result, reader);
} // using dataReader
} // using dbCommand
return result;
} // method::GetBannerImages
您可能已經擁有將讀取器轉換為數據表的功能,如果不只是研究System.Data.Common.DbDataAdapter類的子類,
我在企業庫方面取得了巨大的成功。 這是快速,高效的,並且在執行此路由時,我從未遇到內存泄漏或數據庫連接問題。
無需將變量設置為null
無論如何它們將被GC刪除。
您還需要為實現IDisposable
所有類調用Dispose()
或Close()
。 例如SqlConnection
。
您可以手動執行以下操作:
SqlConnection conn = null;
try
{
// use conn
}
finally
{
if (conn != null)
conn.Close();
}
或自動使用using
塊:
using (SqlConnection = new SqlConnection())
{
// use conn
}
(像你一樣做)
您還可以使用運算符來減少代碼?
:
string str = String.IsNullOrEmpty(StrConnection) ? ConfigurationSettings.AppSettings["ConStr"] : StrConnection;
或??
:
string str = StrConnection ?? ConfigurationSettings.AppSettings["ConStr"];
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.