Как мне предоставить доступ к этому пользовательскому DAL? - PullRequest
1 голос
/ 13 мая 2010

Я пишу пользовательский DAL (VB.NET) для проекта системы заказов. Я хотел бы объяснить, как это кодируется сейчас, и получить некоторые альтернативные идеи, чтобы сделать кодирование против DAL более легким / более читабельным. DAL является частью n-уровневого (не n-слойного) приложения, где каждый уровень находится в своей собственной сборке / DLL.

DAL состоит из нескольких классов, имеющих определенное поведение. Например, существует класс Order, который отвечает за получение и сохранение заказов. Большинство классов имеют только два метода: «Get» и «Save», с несколькими перегрузками для каждого. Эти классы помечены как Friend и видны только DAL (который находится в его собственной сборке).

В большинстве случаев DAL возвращает то, что я буду называть «объектом данных». Этот объект является классом, который содержит только данные и проверку и находится в общей сборке, которую могут прочитать как BLL, так и DAL.

Чтобы обеспечить публичный доступ к DAL, у меня в настоящее время есть статический (модульный) класс, который имеет много общих членов. Упрощенная версия выглядит примерно так:

Public Class DAL
    Private Sub New
    End Sub

    Public Shared Function GetOrder(OrderID as String) as OrderData

        Dim OrderGetter as New OrderClass
        Return OrderGetter.GetOrder(OrderID)

    End Function

End Class

Friend Class OrderClass
    Friend Function GetOrder(OrderID as string) as OrderData
    End Function
End Class

BLL будет вызывать такой заказ:

DAL.GetOrder("123456")

Как вы понимаете, это становится очень громоздким. Я в основном заинтересован в структурировании доступа к DAL, чтобы Intellisense был интуитивно понятен. В настоящее время существует слишком много методов / функций в классе DAL с похожими именами.

У меня была идея разбить DAL на вложенные классы:

Public Class DAL
    Private Sub New
    End Sub

    Public Class Orders
        Private Sub New
        End Sub

        Public Shared Function Get(OrderID as string) as OrderData
        End Function

    End Class

End Class

Таким образом, BLL будет называть так:

DAL.Orders.Get("12345")

Это немного очищает, но оставляет много классов, которые имеют ссылки только на другие классы, что мне почему-то не нравится.

Не прибегая к передаче конкретных инструкций БД (например, предложений where) из BLL в DAL, каков наилучший или наиболее распространенный способ предоставления единой точки доступа для DAL?

Ответы [ 2 ]

1 голос
/ 13 мая 2010

То, что вы сделали, действительно является улучшением. Вы сделали серию Репозиторий классов, которые работают по жизни, чтобы вернуть вам сущности. Вы также можете поместить свои методы записи / обновления / удаления в новый объект Orders и разместить их в одном месте, что хорошо.

Ваша проблема, которую вы подняли в конце, - это проблема, с которой мы все имеем дело. Если вы когда-нибудь задумывались, почему LINQ-to-SQL или LINQ-to-Entities хороши, вот почему. Это связано с интерфейсом IQuerable. Используя любую из этих технологий, ваш метод Get может возвратить IQuerable (Order) (по-видимому, возвращающий каждый возможный объект ордера), с которым вы можете затем выполнить LINQ; это фактически применило бы ваши бизнес-критерии к сгенерированному запросу SQL! Сначала это похоже на магию, но связано с природой IQuerable.

Если вы не используете такого провайдера LINQ 'db', тогда вы должны заработать свой профессиональный лейбл и сделать это по старинке: будьте умны. Вы все еще хотите использовать LINQ-to-object! Ах, да, вы делаете. Вы можете добавить GetByCustomer(CustomerID As Int), который принимает идентификатор клиента и возвращает IEnumerable (Order), и это будет возвращать 0 записей, или 10 или 50, в зависимости от записей. (Ваш объект Customer, вероятно, будет иметь свойство Orders, которое будет возвращать результаты этого метода.) Но вы не хотите продолжать добавлять собственные методы для каждой возможности. Допустим, вы часто хотите получить последний заказ Клиента; Вы, вероятно, хотите добавить GetLatestByCustomer(CustomerID as Int).

Но как насчет того, когда вам нужен только один раз клиент второй заказ . Было бы сумасшествием добавлять метод к вашему объекту DAL, GetSecondOrderByCustomer(), верно? На данный момент мы действительно загромождаем наш объект DAL. В этом случае вы можете использовать LINQ против вашего метода GetByCustomer ():

Dim 2ndOrder As Order = (From O in DAL.Orders.GetByCustomer("123")
                            Order By OrderDate).Skip(1).Take(1)

Теперь, это довольно чисто, понятно, и вы не загромождаете свой DAL тем, что нам нужно было бы рассмотреть довольно специализированный запрос. Обратите внимание, что за кулисами вы получаете каждый заказ для данного клиента! Это не должно быть концом света; Я уверен, что ваша таблица заказов имеет индекс по CustomerID, верно? Но иногда вам нужно получить 60 записей заказов, чтобы получить второй.

Если в какой-то момент у вас возникнет действительно сумасшедшая потребность в запросе (получить все заказы между двумя датами, доставленные в Милуоки, оплаченные кредитной картой, пришедшие по факсу), вам, вероятно, придется предоставить прямую Опция -sql в вашем DAL. Вы хотите бороться, чтобы избежать этого, если можете, потому что тогда вы теряете свою абстракцию. Не могли бы вы добавить Orders.GetBetweenDates(FirstDate As date, SecondDate As date). Да уж . , , но видите опасность? Некоторые более поздние разработчики могут позвонить, чтобы получить все заказы на пару лет, а затем использовать LINQ для дальнейшей фильтрации. Это может легко вызвать сканирование таблицы за кулисами. Это те вещи, которые вы должны учитывать.

Вы должны быть осторожны. Когда вы хотите абстрагироваться (что хорошо!), Вы должны сделать компромиссы. Привлекательность LINQ-to-SQL заключается в том, что вы можете выполнить запрос LINQ, аналогичный приведенному выше примеру, и он просто получит одну запись из базы данных!

0 голосов
/ 14 мая 2010

Одно из изменений, которое я бы предложил, заключалось бы в создании класса DAL для интерфейса и добавлении перегрузок конструктора, которые позволили бы вам внедрять зависимости, такие как компоненты ORM, соединения, команды и т. Д. Это имеет ряд преимуществ: самое главное, что вы можете вводить макеты для модульного тестирования в отдельности, а сам DAL можно моделировать для тестирования уровня.

Это довольно сложный образец, но вот действительно базовый пример схемы, которую я могу предложить

Public Interface IDal
    Function GetData(ByVal OrderID As String) As String
End Interface

Public Class Dal : Implements IDal
    Private _connection As IDbConnection

    Public Sub New()
        Me.New(IoC.Resolve(Of IDbConnection))
    End Sub

    Friend Sub New(ByVal Connection As IDbConnection)
        _connection = Connection
    End Sub

    Public Function GetData(ByVal OrderID As String) As String Implements IDal.GetData
        ' Use injected connection and Get the data
    End Function
End Class

Имейте в виду, это просто для иллюстрации шаблона, который вы можете изменить по мере необходимости. Обратите внимание на область Friend конструктора. Это на самом деле предназначено только для вызова классами и сборками Frield, такими как тестовые сборки, хотя вы, безусловно, можете сделать это общедоступным и позволить потребляющим слоям внедрять все свои собственные зависимости.

Этот бит "IoC.Resolve (Of IDbConnection)" включает понятие использования контейнера Inversion of Control (IoC) по вашему выбору, хотя в действительности это не нужно. Просто убедитесь, что вы обновили свои зависимости, используя конкретные реализации по умолчанию, если ни одна не была внедрена. Dependency Injection и IoC - действительно мощные шаблоны, которые идеально подходят для использования в DAL. Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...