0

我正在实现一个穷人的 ORM 一个遗留应用程序(.NET 2.0 Web 应用程序,手工编码的 SQL 查询)。我有两个数据类:CustomerOrder

Public Class Customer
    Public Property CustomerId As Integer
    Public Property CustomerName As String
    Public Property Orders As List(Of Order)
End Class

Public Class Order
    Public Property OrderId As Integer
    Public Property OrderItem As String
End Class

我正在使用 aSqlDataReader手动将 SQL 结果映射到Customer该类的实例:

Dim connection As New SqlConnection(connectionString)
Dim command As New SqlCommand(sql, connection)
Dim reader As SqlDataReader()

connection.Open()

reader = command.ExecuteReader()

Dim customer As New Customer()

While reader.Read
    With customer
        .CustomerId =   reader("CustomerId")
        .CustomerName = reader("CustomerName")
        .Orders =       getOrdersByCustomerId(reader("CustomerId"))   ' get orders
    End With
End While

connection.Close()

为了填充Customer.Orders,我调用了一个返回 a 的函数List(Of Order)

Private Function getOrdersByCustomerId(ByVal customerId As Integer) As List(Of Order)

    Dim connection As New SqlConnection(connectionString)
    Dim command As New SqlCommand(sql, connection)
    Dim reader As SqlDataReader()

    connection.Open()

    reader = command.ExecuteReader()

    Dim orders As New List(Of Order)

    While reader.Read
        Dim order As New Order
        With order
            .OrderId =   reader("OrderId")
            .OrderItem = reader("OrderItem")
        End With
        orders.Add(order)
    End While

    connection.Close()

    Return orders

End Function

我担心这种方法的性能,即如果我要拉多个Customer's. 对于每次Customer拉取,我必须再次访问数据库(打开另一个连接),并获取该给定客户的订单。如果我没记错的话,积累大量打开的连接不需要很多记录。

我的问题有两个:

  1. 如何确定正在建立的新连接的数量以及是否会遇到任何连接池或其他此类 .NET 强加的限制?
  2. 有没有更好的办法?(见下面的评论)

我的一个想法是将SQLConnection调用类中创建的对象传递给getOrdersByCustomerId函数,并让该函数使用(显然?)已经打开的连接。我没有测试它,因为我不知道如何确定它是否比我现有的方法更好。想法?


背景:

我正在创建一个搜索 Web 服务,它返回 JSON 以供客户端处理。该服务采用单个搜索参数,对不同的表执行多次查找,然后返回自定义 JSON 对象。例如,如果用户输入一个看似名称的内容,我会在Customers表中搜索前n 个客户的列表,并在Orders表中搜索具有该名称的客户的前n 个订单。

4

4 回答 4

3

首先是你错过了Using Statement,所以你的代码应该是这样的,而不是依赖于Garbage Collector自动处理它。

Using connection As New SqlConnection("connectionString")
    Using command As New SqlCommand("sql", connection)
        Using reader As SqlDataReader = Nothing

            connection.Open()

            reader = command.ExecuteReader()

            Dim customer As New Customer()

            While reader.Read
                If True Then
                    customer.CustomerId = reader("CustomerId")
                    customer.CustomerName = reader("CustomerName")
                    customer.Orders = getOrdersByCustomerId(reader("CustomerId"))
                End If
            End While
            connection.Close()
        End Using
    End Using
End Using

回到关于性能的原始查询

我会DataTable在记录大量的情况下使用。请记住,DataTable对象在使用后以与上述类似的方式被使用语句处理。所以添加记录不需要进行迭代。

再次访问数据库

您是否可以考虑使用ViewStateSession,如果您发现数据有任何变化,您也可以使用SQLDependency.

getOrdersByCustomerId(reader("CustomerId"))

您是否可以将所有与客户相关的信息都带入表单加载中,并将其保存在其中ViewState?在数据阅读器中,不希望一遍又一遍地访问数据库。所以,最后访问ViewStateDataReader Iteration 中的变量。

于 2012-05-30T22:35:28.650 回答
3

打开和重新打开连接几乎是免费的。因此,最好打开连接并尽快处理它,最好是在 using 块中。

Max Pool Size=1;您可以通过添加到连接字符串来测试连接泄漏。这会将可用连接数限制为 1。如果泄漏连接,则会收到错误消息。确保不要在生产中使用此设置。

出于性能考虑,您通常会避免为大型集合中的每一行访问数据库。因此,您可以编写一个新的查询或过程来返回所有相关客户的所有订单。但是在实践中,这是一个不寻常的查询。您通常会显示客户列表,并且只有当最终用户放大该客户时,您才会检索订单列表。

于 2012-05-30T22:30:29.333 回答
2

在这个问题的数据库方面工作。
您没有显示任何用于检索记录的 sql 命令

例如,当您通过 ID 加载客户时,尝试同时加载其订单。

SELECT CUSTOMERS.*, ORDERS.* 
FROM CUSTOMERS LEFT JOIN ORDERS 
     ON CUSTOMERS.ID = ORDERS.CUSTOMERID
WHERE CUSTOMERS.ID = @custID

让这些数据在内存中创建客户及其订单,而无需两次访问数据库。

于 2012-05-30T22:46:34.307 回答
2

除非您关闭了池,否则不要担心连接,如果您有,您就不会问这个问题。

如果你想让事情变得更清楚一点,虽然 using 块是个好主意。

Using connection = new SqlConnection(ConnectionString)
' Insert code here 
End Using

连接将在最后使用时被释放,因为您处于默认行为,连接将返回到池中以在下次您的代码(实际上池由 appdomain 完成)需要一个时重用。如果在默认时间段(我似乎记得 2 分钟)内什么都不需要它,那么它会在那时完全处理掉。

PS对于任何实现 IDisposable 的方法本地的东西使用块是一个好主意。

为每个订单点击服务器,没有明确的答案。比如说一个订单页面,然后从中创建一个订单对象的集合会提高性能,只要你没有得到一堆你不太可能需要的东西。即只获取显示所需的数据,如果有更多负载,则使用某种延迟加载方案并在需要时获取数据,或者具有不同的类,例如 OrderSummary、OrderDetail。

于 2012-05-30T22:47:16.473 回答