调用 ExecuteReader 时从 DAL 基类处置 SqlConnection

发布于 2024-07-26 23:30:49 字数 2426 浏览 4 评论 0原文

我被分配到一个项目,其中 DAL 由一个基类组成,该基类具有返回 IDataReader、一个对象(int、字符串等)或一个 DataSet 的函数。 还存在 ExecuteNonQuery 函数。 该DAL仅访问USP(SQL Server),并使用MS的SqlHelper来执行查询。 以下是来自基类的两个示例函数:

    protected IDataReader ExecuteReader(string storedProcedure, params object[] parameterValues)
    {
        SqlConnection HConnection = new SqlConnection(myConnString);
        IDataReader ret = null;
        try
        {
            ret = SqlHelper.ExecuteReader(HConnection, storedProcedure, parameterValues);
        }
        catch (Exception ex)
        {
            HanldeError(ex, storedProcedure, parameterValues);
        }
        return ret;
    }

    protected object ExecuteScalar(string storedProcedure, params object[] parameterValues)
    {
        using (SqlConnection HConnection = new SqlConnection(myConnString))
        {
            object ret = null;
            try
            {
                ret = SqlHelper.ExecuteScalar(HConnection, storedProcedure, parameterValues);
            }
            catch (Exception ex)
            {
                HanldeError(ex, storedProcedure, parameterValues);
            }
            return ret;
        }
    }

其他类从该基类派生,创建特定于任务的 DAL 类,例如:

public class Orders : BaseDal {
    public IDataReader GetOrdersList(int clientId, int agentId)
    {
        return ExecuteReader("usp_Orders_GetOrdersList", clientId, agentId);
    }
    ...
}

然后是调用 DAL 函数并用数据填充对象(例如 Order 对象)的 BLL 类基于从 IDataReader 对象读取的数据:

    public Order[] GetOrdersList(int ClientIDX, int AgentIDX)
    {
        List<Order> ret = null;
        using (IDataReader dr = objDAL.GetOrdersList(ClientIDX, AgentIDX))
        {
            if (dr != null)
            {
                ret = new List<Order>();
                while (dr.Read())
                {
                    ret.Add(xReadOrder(dr, 0));
                }
            }
        }
        return ret.ToArray();
    }

我的问题是这样的 - 如果您查看从 BaseDal 获取的代码,您会注意到只有 ExecuteScalar 实际上终止了 SqlConnection 对象(using 语句) - 所有情况都是如此我在那里的职能。 使用 ExecuteReader 我无法做到这一点,因为我返回一个打开的 SqlDataReader 对象并关闭连接将使读取器无效。 我从 DAL 获取和使用 IDataReader 的所有代码都使用 using 语句,但是 SqlConnection 对象是否也被释放,或者是否在稍后阶段被 GC 处理,不尽快释放它会损害连接池? 如果是这样,该如何治疗?

另外,是否有比上述方法更好的创建 DAL 的方法? 我不太关心与数据存储无关的 DAL,我们只需要一个可靠且易于维护的 DAL,一个可以从多个线程获取多个并发连接的 DAL。

预先感谢您对此的任何帮助。

I've been assigned on a project where the DAL consists of a base class with functions to return IDataReader, an Object (int, string and the like), or a DataSet. An ExecuteNonQuery function also exists. This DAL only accesses USPs (SQL Server), and is using MS's SqlHelper to execute the queries. Here's two sample functions from the base:

    protected IDataReader ExecuteReader(string storedProcedure, params object[] parameterValues)
    {
        SqlConnection HConnection = new SqlConnection(myConnString);
        IDataReader ret = null;
        try
        {
            ret = SqlHelper.ExecuteReader(HConnection, storedProcedure, parameterValues);
        }
        catch (Exception ex)
        {
            HanldeError(ex, storedProcedure, parameterValues);
        }
        return ret;
    }

    protected object ExecuteScalar(string storedProcedure, params object[] parameterValues)
    {
        using (SqlConnection HConnection = new SqlConnection(myConnString))
        {
            object ret = null;
            try
            {
                ret = SqlHelper.ExecuteScalar(HConnection, storedProcedure, parameterValues);
            }
            catch (Exception ex)
            {
                HanldeError(ex, storedProcedure, parameterValues);
            }
            return ret;
        }
    }

Other classes derive from this base class, creating task-specific DAL classes, for instance:

public class Orders : BaseDal {
    public IDataReader GetOrdersList(int clientId, int agentId)
    {
        return ExecuteReader("usp_Orders_GetOrdersList", clientId, agentId);
    }
    ...
}

Then there are BLL classes that call the DAL functions, and fill objects (for example an Order object) with the data based on the data read from the IDataReader object:

    public Order[] GetOrdersList(int ClientIDX, int AgentIDX)
    {
        List<Order> ret = null;
        using (IDataReader dr = objDAL.GetOrdersList(ClientIDX, AgentIDX))
        {
            if (dr != null)
            {
                ret = new List<Order>();
                while (dr.Read())
                {
                    ret.Add(xReadOrder(dr, 0));
                }
            }
        }
        return ret.ToArray();
    }

My question is this - if you'll look at the code taken from BaseDal, you'll notice only ExecuteScalar actually terminates the SqlConnection object (the using statement) - this is the case with all my functions there. With ExecuteReader I cannot do that, as I'm returning an open SqlDataReader object and closing the connection will invalidate the reader.
I have all the code getting and using an IDataReader from the DAL use the using statement, but is the SqlConnection object being disposed as well, or is it being GC'ed at a later stage, hurting the connection pooling by not freeing it up sooner? If so, how can this be treated?

Also, is there a better approach to creating a DAL than the one described above? I'm less concerned about data store agnostic DAL, we only need a solid and easy to maintain one, one that can take many concurrent connections from many threads.

Thanks in advance for any help on this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦纸 2024-08-02 23:30:49

如果您在执行命令时指定CommandBehavior.CloseConnectionSqlDataReader 将关闭连接。 不过,总感觉有点丑。

相反,将 SqlConnection 传递到方法中并使用它。 然后调用者可以控制何时处理它。 或者,采用 Action 与打开的读取器一起执行,并在执行操作后使该方法关闭读取器和连接。 当然,该行动必须为读者做一切需要做的事情。

SqlDataReader will close the connection if you specify CommandBehavior.CloseConnection when you execute the command. However, it feels a bit ugly anyway.

Instead, pass a SqlConnection into the method and use that. Then the caller has control over when that's disposed. Alternatively, take an Action<SqlDataReader> to execute with the open reader, and make the method close both the reader and the connection, after executing the action. That action would have to then do everything it needed to with the reader, of course.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文