Удаление SqlConnection из базового класса DAL при вызове ExecuteReader

2

Я был назначен в проекте, где DAL состоит из базового класса с функциями для возврата IDataReader, Object (int, string и т.п.) или DataSet. Также существует функция ExecuteNonQuery. Этот DAL только обращается к USPs (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);
    }
    ...
}

Затем существуют классы BLL, которые вызывают функции DAL, и заполняют объекты (например, объект Order) данными на основе данных, считываемых из объекта 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 и закрытие соединения приведет к недействительности читателя. У меня есть весь код, получающий и использующий IDataReader из DAL, используя инструкцию using, но также и объект SqlConnection, или он GC на поздней стадии, ущемляя объединение пулов, не высвобождая его раньше? Если да, то как это можно лечить?

Кроме того, существует ли лучший подход к созданию DAL, чем описанный выше? Я меньше беспокоюсь об агностическом хранилище данных DAL, нам нужен только прочный и простой в обслуживании, который может принимать много параллельных соединений из многих потоков.

Заранее благодарим за помощь.

Теги:
sqlconnection
data-access-layer

1 ответ

4
Лучший ответ

SqlDataReader закроет соединение, если вы укажете CommandBehavior.CloseConnection при выполнении команды. Тем не менее, он чувствует себя немного уродливым в любом случае.

Вместо этого передайте a SqlConnection в метод и используйте это. Тогда вызывающий имеет контроль над тем, когда он расположен. В качестве альтернативы, выполните Action<SqlDataReader> для выполнения с открытым считывателем и сделайте метод закрытым как для чтения, так и для соединения после выполнения действия. Разумеется, это действие должно было бы сделать все, что нужно для читателя.

  • 0
    Благодарю. Хотя вы считаете это «уродливым», использование CommandBehavior.CloseConnection кажется мне лучшим вариантом, так как именно это SqlHelper делает внутренне, когда передает строку соединения (в отличие от объекта SqlConnection ). Передача SqlConnection в метод не возможна, поскольку она будет противоречить разделению DAL / BLL, которое я пытаюсь сохранить. Подход Action<SqlDataReader> я не знаком, но кажется немного трудным. Просто чтобы убедиться - можете ли вы указать мне хорошее место, чтобы на самом деле увидеть, что именно это означает?
  • 0
    Хм, нелегко (я сейчас пытаюсь что-то исправить) - но вы бы использовали лямбда-выражение, чтобы сказать «когда у вас открыт читатель, это то, что я хочу с ним сделать», в основном.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню