简体   繁体   English

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

[英]Am I closing this SQL connection in a C# function appropriately?

In an attempt to close my question on connections remaining open and exceeding the maximum pool , I'm trying tor rewrite the function that is used to connect to our database. 为了试图解决有关保持打开状态并超过最大池数的连接的问题 ,我试图重写用于连接数据库的函数。

The function exists within a homegrown compiled library. 该函数存在于本地编译的库中。 using reflector I can see the code looks like this: 使用反射器,我可以看到代码如下:

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();
}

I'm planning on amending this to read 我正计划对此进行阅读

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();
    }
}

and then recompiling the dll. 然后重新编译dll。 Given that an instance of SQLProvider() is typically created at the top of a public class, and then that instance is used within class members (eg: 假定通常在公共类的顶部创建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;
        }
    }
}

am I going about this the right way? 我要这样做正确吗? It seems to me the connection will be disposed of before the data has actually been retrieved. 在我看来,连接将在实际检索数据之前被处理掉。 Also, Visual Studio tells me that SQLProvider() must be implicitly convertible to System.IDisposable - how would I go about implementing this? 另外,Visual Studio告诉我SQLProvider()必须隐式转换为System.IDisposable我将如何实现这一点?

I tried wrapping all the members of class Banner in a using (DSLibrary.DataProviders.SqlProvider db = new DSLibrary.DataProviders.SqlProvider(Defaults.ConnStr)){} statement but intellisense then displays a "Invalid token 'using' in class, struct, or interface member declaration" error. 我试过在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)){} ” ,或接口成员声明”错误。

What is the best way to go about this? 最好的方法是什么?

UPDATE I've tried disassembling adjusting and recompiling the DSLibrary, but as CHris_Lively says, I thinkit's doing nothing for me. 更新我曾尝试拆解调整和重新编译DSLibrary,但是正如CHris_Lively所说,我认为它对我没有任何帮助。 Changing the instance in question to what I preceive to be a more standard format works so far: 到目前为止,将有问题的实例更改为我认为是更标准的格式是可行的:

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;
    }
}

I'm about to look into the Enterprise library, seems like it might be the way forward. 我将要研究企业库,看来这可能是前进的方向。

It is not recommended to hold on to connections any longer than required (See also Chapter 14 of Improving .NET Application Performance and Scalability: Patterns and Practices from Microsoft Press). 不建议将连接保留的时间不要超过要求的时间(另请参见“ 提高.NET应用程序的性能和可伸缩性: Microsoft Press的模式和实践”的第14章)。

In practice I'd change your class to instead not have the SqlConnection (or SqlDataAdapter or SqlCommandBuilder ) as a member on the class (if you must , then you should implement the IDisposable pattern), but instead create new instances, wrapped in using statements on the class methods that need to use them. 在实践中,我将更改您的类,以使其不具有SqlConnection(或SqlDataAdapterSqlCommandBuilder )作为类的成员(如果必须 ,则应实现IDisposable模式),而是创建新实例,并使用using语句包装关于需要使用它们的类方法。

I DO NOT think you are doing it correctly. 我认为您的做法不正确。 As soon as you hit the end of the using block, the SqlConnection variable will become unusable . 一旦您到达using块的末尾,SqlConnection变量将变得不可用。 If you want to use it outside the constructor, dont put the using {} around the SqlConnection variable (The sqlcommand variable MyCommand is using it indirectly outside the constructor). 如果要在构造函数外部使用它,请不要在SqlConnection变量周围使用using {}(sqlcommand变量MyCommand在构造函数外部间接使用它)。
Instead, make you SqlProvider class implement IDisposable, and call Dispose on the MyCommand, MyDataAdapter, MyDataSet etc. variables there. 相反,让您的SqlProvider类实现IDisposable,然后在其中的MyCommand,MyDataAdapter,MyDataSet等变量上调用Dispose。
You probably should have something like this in your SqlProvider class : 您可能在SqlProvider类中应该有以下内容:

    public void Dispose()
    {
        if (MyCommand != null)
        {
            MyCommand.Dispose();
        }
        //... Similarly for MyDataAdapter,MyDataSet etc.
    }

Your class needs to implement the IDisposable interface if you want to use it in a using block. 如果要在using块中使用它,您的类需要实现IDisposable接口。 See http://msdn.microsoft.com/en-us/library/system.idisposable.dispose%28v=VS.100%29.aspx for guidelines on dispose() and IDisposable. 有关dispose()和IDisposable的准则,请参见http://msdn.microsoft.com/zh-cn/library/system.idisposable.dispose%28v=VS.100%29.aspx

You're close. 你近了 However, a couple issues. 但是,有几个问题。

First, it looks like that whole DSLibrary isn't buying you anything at all. 首先,整个DSLibrary似乎根本没有买任何东西。

When doing data access you typically want to structure it where acquiring the connection and executing the command are in the same function. 进行数据访问时,通常需要在获取连接和执行命令具有相同功能的地方进行结构化。 You're methods should only return the result of the operation. 您的方法只应返回操作结果。 This way you can cleanly use the IDisposable interface of the connection, command, and reader. 这样,您可以干净地使用连接,命令和阅读器的IDisposable接口。

The following example uses Enterprise Library . 以下示例使用企业库 Note that the Db doesn't have a using clause. 请注意,Db没有using子句。 It doesn't implement IDisposable. 它没有实现IDisposable。 Instead, the command is responsible for letting go of the connection when it goes out of scope: 相反,该命令在超出范围时负责释放连接:

    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

You probably already have something that will convert a reader to a datatable, if not just look into subclassing the System.Data.Common.DbDataAdapter class 您可能已经拥有将读取器转换为数据表的功能,如果不只是研究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. 这是快速,高效的,并且在执行此路由时,我从未遇到内存泄漏或数据库连接问题。

There is no need to set variables to null - anyway they will be deleted by GC. 无需将变量设置为null无论如何它们将被GC删除。

Also you need to call Dispose() or Close() for all classes that implements IDisposable . 您还需要为实现IDisposable所有类调用Dispose()Close() eg SqlConnection . 例如SqlConnection

You can do that manually: 您可以手动执行以下操作:

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

or automatically using using block: 或自动使用using块:

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

(as you do) (像你一样做)

Also you can decrease your code a bit using operator ? 您还可以使用运算符来减少代码? :

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

or ?? ?? :

string str = StrConnection ?? ConfigurationSettings.AppSettings["ConStr"];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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