[英]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.