4

为了解决我关于保持打开和超过最大池的连接的问题,我正在尝试重写用于连接到我们的数据库的函数。

该函数存在于一个自制的编译库中。使用反射器我可以看到代码如下所示:

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- 我将如何实现这一点?

我尝试将 的所有成员包装class Banner在一个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;
    }
}

我即将研究企业库,似乎这可能是前进的方向。

4

4 回答 4

4

不建议保持连接的时间超过所需时间(另请参阅《提高 .NET 应用程序性能和可扩展性: Microsoft Press 的模式和实践》的第 14 章)。

在实践中,我会将您的类更改为不将 SqlConnection (或SqlDataAdapteror SqlCommandBuilder)作为类的成员(如果必须,那么您应该实现该IDisposable模式),而是创建新实例,包装在类上的 using 语句中需要使用它们的方法。

于 2010-06-23T11:14:52.920 回答
2

我不认为你做对了。一旦你到达 using 块的末尾, SqlConnection 变量将变为 unusable 。如果要在构造函数之外使用它,请不要将 using {} 放在 SqlConnection 变量周围(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/en-us/library/system.idisposable.dispose%28v=VS.100%29.aspx

于 2010-06-23T11:05:59.167 回答
1

你很近。但是,有几个问题。

首先,看起来整个 DSLibrary 根本没有给你买任何东西。

在进行数据访问时,您通常希望将其构造为获取连接和执行命令在同一函数中。你的方法应该只返回操作的结果。这样您就可以干净利落地使用连接、命令和阅读器的 IDisposable 接口。

以下示例使用Enterprise Library。请注意,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 类

I've had tremendous success with the Enterprise Library. It's fast, efficient, and when going this route I've never had memory leaks or db connection issues.

于 2010-06-23T14:31:46.900 回答
0

无需将变量设置为null- 无论如何它们将被 GC 删除。

您还需要Dispose()Close()所有实现IDisposable. 例如SqlConnection

您可以手动执行此操作:

SqlConnection conn = null;
try
{
    // use conn
}
finally
{
    if (conn != null)
        conn.Close();
}

或自动使用using块:

using (SqlConnection = new SqlConnection())
{
    // use conn
}

(像你一样做)

您也可以使用 operator 减少代码?

string str = String.IsNullOrEmpty(StrConnection) ? ConfigurationSettings.AppSettings["ConStr"] : StrConnection;

??

string str = StrConnection ?? ConfigurationSettings.AppSettings["ConStr"];
于 2010-06-23T11:01:01.847 回答