3

基本上,我们有三个数据库可以从中获取数据。一个是 SQL Server 数据库,一个是 Access 数据库(连接起来特别烦人,因为我们必须映射网络驱动器等),最后一个是 Oracle 数据库,当 IT 最终授予我们权限时。

我正在考虑创建一个帮助函数,使查询这些数据库中的任何一个尽可能容易。理想情况下,我想创建一个二维数组

Dim myEasyResultArray(10,10) as String
myEasyResultArray = DatabaseHelper("Access", "SELECT * FROM Employee")

这是一个好的设计决策吗?另外,我怎样才能让数组的大小合适?我可以这样做吗?

Dim myEasyResultArray = DatabaseHelper("Access", "SELECT * FROM Employee")

这应该是一个模块还是一个类?我真的不需要共享变量,

4

2 回答 2

4

我会尝试将所有数据访问逻辑放入数据访问层。理想情况下,这将位于单独的库和命名空间中,但并非必须如此。我会使用类,通常每个表/实体一个,并将所有类设计为无状态(因此您不必重用数据访问对象的同一实例,您可以在需要时随时实例化一个新实例访问数据库)。

我不会让它返回数组,而是让它返回数据对象(通常称为 DTO - 数据传输对象)。如果可能的话,我会保持 DTO 类尽可能干净,只包含公共属性而不包含方法。数据访问类都应该实现接口,以便可以创建每个接口的多个版本。一个用于 Access,一个用于 Oracle,一个用于 SQL,等等。然后,无论我需要在哪里访问数据库(希望只在我的业务层中,而不是在我的 UI 层中),我都会通过它们“请求适当的数据访问对象”通用”接口类型(因此需要一个工厂类将正确的具体数据访问对象类型注入我的业务对象)。

这是一个真正简单的 DTO 示例:

Public Class Employee
    Public Id As Guid
    Public Name As String
    Public StartDate As Date
End Class

这是一个示例数据访问接口

Public Interface IEmployeeDataAccess
    Function GetEmployee(id As Guid) As Employee
    Function GetEmployees() As List(Of Employee)
End Interface

下面是一个数据访问类的示例:

Public Class SqlEmployeeDataAccess
    Inherits IEmployeeDataAccess

    Public Function GetEmployee(id As Guid) As Employee Implements IEmployeeDataAccess.GetEmployee
        Dim employee As New Employee()
        ' Connect to SQL DB and populate employee DTO object
        Return employee
    End Function

    Public Function GetEmployees() As List(Of Employee) Implements IEmployeeDataAccess.GetEmployees
        Dim employees As New List(Of Employee)()
        ' Connect to SQL DB and populate list of employee DTO objects
        Return employees
    End Function
End Interface

然后,您可能会调用类似的类AccessEmployeeDataAccessOracleEmployeeDataAccess这些类也实现了 IEmployeeDataAccess 接口。然后,同样在数据访问层,我将为每个受支持的 DB 提供程序创建一个工厂类。我会让所有 DataAccess 工厂实现相同的接口,如下所示:

Public Interface IDataAccessFactory
    Function NewEmployeeDataAccess() As IEmployeeDataAccess
End Interface

Public Class SqlDataAccessFactory
    Implements IDataAccessFactory

    Public Function NewEmployeeDataAccess() As IEmployeeDataAccess
        Return New SqlEmployeeDataAccess()
    End Function
End Class

然后,在我的商务舱中,我可能会做这样的事情:

Public Class EmployeeBusiness
    Public Sub New(employeeDataAccess As IEmployeeDataAcess)
        _employeeDataAccess = employeeDataAccess
    End Sub

    Private _employeeDataAccess As IEmployeeDataAcess

    Public Function GetEmployee(id As Guid) As Employee
        Return _employeeDataAccess.GetEmployee(id)
    End Function
End Class

然后在我的商业工厂中,我会做这样的事情:

Public Class BusinessFactory
    Public Sub New()
        Select Case dataAccessType
            Case "SQL"
                _dataAccessFactory = New SqlDataAccessFactory()
            Case "Oracle"
                _dataAccessFactory = New OracleDataAccessFactory()
            Case "Access"
                _dataAccessFactory = New AccessDataAccessFactory()
        End Select
    End Sub

    _dataAccessFactory As IDataAccessFactory

    Public Function NewEmployeeBusiness() As IEmployeeBusiness
        Return New EmployeeBusiness(_dataAccessFactory.NewEmployeeDataAccess())
    End Function
End Class

这可以通过使用一组可与任何数据库提供程序一起使用的数据访问对象来大大简化。为此,您只需要使用基本 ADO 类型,例如 IDbConnection 而不是 SqlConnection,以及 IDbCommand 而不是 SqlCommand。然后,只要 DataAccess 类需要一个,您的数据访问对象就可以请求一个可以创建新连接等的 DB Provider 工厂。但是,当您只是调用存储过程或其他东西时,这更容易做到。通常,尤其是当您在代码中动态构建 SQL 语句时,提供程序之间存在太多差异,因此您不能只对所有数据库提供程序使用相同的 DataAccess 类。

但是,这只是我...

于 2012-06-11T14:17:22.280 回答
1

我看到你的提议存在一个大问题。

第一个是我经常看到程序员想要使用类似于这种形式的方法来构建数据库帮助:

DataTable GetData(string sql)

这里的重点是该方法接受一个 sql 字符串,不提供查询参数。这是错误的。这是一种反模式,因为它鼓励您(几乎强迫您)将 sql数据编码为查询代码的一部分。您必须提供一些机制,以便将查询参​​数作为单独的数据正确传递。数组很常见,但这不是唯一的方法。我通常也不提供只接受字符串的重载,因为它不可避免地会导致滥用。如果要发送不带参数的查询,则传递一个空数组。这样就很清楚这就是您想要的,并且将鼓励使用您的数据库助手的任何人学习以正确的方式使用参数。

还有其他可以改进的地方,但在我看来,这是主要问题。

于 2012-06-11T14:30:27.577 回答