【问题标题】:How should I provide access to this custom DAL?我应该如何提供对此自定义 DAL 的访问权限?
【发布时间】:2011-02-19 03:19:00
【问题描述】:

我正在为订购系统项目编写自定义 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")

这稍微清理了一下,但它留下了很多只引用其他类的类,出于某种原因我不喜欢这些类。

在不求助于将 DB 特定指令(如 where 子句)从 BLL 传递到 DAL 的情况下,为 DAL 提供单点访问的最佳或最常见做法是什么?

【问题讨论】:

    标签: .net vb.net data-access-layer


    【解决方案1】:

    你所做的确实是一种进步。您已经创建了一系列 Repository 类,这些类的工作就是为您返回实体。您还可以将 Write/Update/Delete 方法放在新的 Orders 对象中,并将这些东西放在一个地方,这很好。

    你最后提出的问题是我们都处理的问题。如果您曾经想知道为什么 LINQ-to-SQL 或 LINQ-to-Entities 很好,这就是原因。它与 IQuerable 接口有关。使用这些技术中的任何一种,您的 Get 方法可以返回一个 IQuerable(Order) (似乎返回每个可能的订单对象),然后您可以针对它执行 LINQ;这实际上会将您的业务标准应用于生成的 SQL 查询!乍一看似乎很神奇,但这与 IQuerable 的性质有关。

    如果您使用这样的 'db' LINQ 提供程序,那么您必须赢得您的专业标签并以老式的方式来做:聪明点。您仍然想利用 LINQ-to-object!哦,是的。您可以添加一个GetByCustomer(CustomerID As Int),它接受一个客户 ID 并返回一个 IEnumerable(Order),这将返回 0 条记录,或者 10 条或 50 条记录,具体取决于记录。 (您的 Customer 对象可能有一个 Orders 属性,该属性将返回此方法的结果。)但是您不想继续为每种可能性添加自定义方法。假设您经常想获取客户的最新订单;你可能想添加一个GetLatestByCustomer(CustomerID as Int)

    但是当您需要时,只需一次,客户第二次订购。给你的 DAL 对象添加一个方法会很疯狂,GetSecondOrderByCustomer(),对吧?在这一点上,我们真的弄乱了我们的 DAL 对象。在这种情况下,您可以针对 GetByCustomer() 方法使用 LINQ:

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

    现在,这非常干净、清晰,而且您不会因为我们必须考虑的非常专业请求而弄乱您的 DAL。请注意,在幕后,您将获得给定客户的每一份订单!这不应该是世界末日;我确定您的 Orders 表有一个按 CustomerID 的索引,对吗?但是,有时您会返回 60 条订单记录来获取第二条记录。

    如果在某个时候您有一个非常疯狂的查询需求(获取两个日期之间的所有订单,交付到密尔沃基威斯康星州,通过信用卡支付,通过传真收到)那么您可能必须提供直接DAL 中的 -sql 选项。如果可以的话,你想努力避免这种情况,因为那样你就失去了抽象。可以加Orders.GetBetweenDates(FirstDate As date, SecondDate As date)。是的 。 . .但看到危险了吗?一些后来的开发人员可能会调用它来获得几年内的所有订单,然后使用 LINQ 进一步过滤。这很容易在幕后引起表扫描。这些是您必须考虑的类型。

    你必须谨慎。当你想抽象时(这很好!),你必须做出权衡。 LINQ-to-SQL 等的吸引力在于您可以执行类似于上面示例的 LINQ 查询,它只会从数据库中获取一条记录!

    【讨论】:

      【解决方案2】:

      我建议的一个更改是将 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)”位引入了使用您选择的控制反转 (IoC) 容器的概念,尽管它并不是真正需要的。如果没有注入,请确保使用默认的具体实现来新建依赖项。依赖注入和 IoC 是非常强大的模式,非常适合在 DAL 中使用。希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-06
        • 1970-01-01
        • 2019-05-11
        相关资源
        最近更新 更多