我应该如何提供对此自定义DAL的访问权限?

时间:2010-05-13 14:43:04

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

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

这清理了一下,但它留下了很多只引用其他类的类,我不喜欢这些类。

不使用从BLL到DAL的DB特定指令(如where子句),为DAL提供单点访问的最佳或最常见做法是什么?

2 个答案:

答案 0 :(得分:1)

你所做的确实是一种进步。您已经制作了一系列 Repository 类,这些类是生活中的工作,它可以让您返回实体。您也可以将新的Orders对象中的Write / Update / Delete方法放在一个地方,这很好。

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

如果你使用这样的'db'LINQ提供商,那么你必须获得专业标签,并采用老式的方式:聪明。您仍然希望利用LINQ到对象!哦,是的,你这样做。您可以添加一个GetByCustomer(CustomerID As Int)来获取客户ID并返回IEnumerable(订单),这将返回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个订单记录,只是为了得到第二个。

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

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

答案 1 :(得分:0)

我建议的一个改变是将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中使用。希望这会有所帮助。