繁体   English   中英

我是否可以在C#函数中适当关闭此SQL连接?

[英]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(或SqlDataAdapterSqlCommandBuilder )作为类的成员(如果必须 ,则应实现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.

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