IEnumerable

时间:2019-03-21 19:25:43

标签: .net vb.net lazy-loading ienumerable

首先道歉,如果应该在代码审查而不是在这里。我发现这里只是显示伪代码。

我有一个从数据库中加载的对象,该对象又具有从数据库中获取的惰性加载属性。

Public Class Item

    Public Sub New(pRow as Datarow)
        Me.ID = CLng(pRow.Item(“ID”))
        ‘ Fill other properties from datarow
    End Sub

    Private _Tags as List(Of Tag)

    Public Readonly Property ID as Long = 0

    Public Readonly Property Tags as List(Of Tag)
      Get
        If _Tags Is Nothing Then _Tags = LoadTagsFromDB(Me.ID)
      End Get
    End Property

End Class

现在这很好,它允许我加载对象的实例。使用其属性,如果我需要标签,我可以抓住它们一次击中数据库。

当我有一个Ienumerable(Of Item)

时,会发生此问题

在某些情况下,我的收藏数量可能超过50,000 +

这显然意味着,当我抓取集合然后对其进行迭代时,在访问每个项目实例的Tags属性时,我会过度地锤击数据库。

我已经按照以下方式重新编写了代码。

Public Class Item

    Public Sub New(pRow as Datarow)
        Me.ID = CLng(pRow.Item(“ID”))
        ‘ Fill other properties from datarow
    End Sub

    Public Readonly Property ID as Long = 0

    Public Readonly Property Tags as List(Of Tags) = Nothing

    Public Sub SetTags(pDictionary as Dictionary(Of Long, List(Of Tag))
      If pDictionary.ContainsKey(Me.ID) Then
        _Tags = pDictionary.Item(Me.ID)
      Else
        _Tags = New List(Of Tag)
      End If
    End Sub

End Class

然后,我可以执行以下操作。

‘ Grab the unique ids from the collection 
Dims ids = ListOfItems.Select(function(x) x.ID).Distinct

‘ One query, giant result set.
Dim d = SQLToGetAllTagsWithIDs(IDs)

For Each o As Item in ListOfItems
  o.SetTags(d)
Next

这是完美的,而且几乎是无限快的,但是当使用单个Item实例或不调用.SetTags时,.Tags属性什么都不是

我已经混合并匹配了这两种情况,因此,如果不调用它,它将首先回退并通过机制通过机制获得它,但这使我回到了第一种情况,即其他开发人员将允许无法实现SetTag的惰性机制存在或存在其目的。

我想我的问题是,我是否不知道某种模型或首选方式来做我想做的事,而我却无法实现两全其美?我很难在Google上搜索这个问题,因为很难解释。

希望这是有道理的,希望有解决方案,如果没有,我想我会坚持下去。

1 个答案:

答案 0 :(得分:1)

您可以在使用静态成员将逻辑机制隐藏在类中的同时自动化逻辑。使用静态对象可使每个Item都知道其他Item,从而使逻辑可以在Item类内移动。

Public Class Item

    Private Shared ReadOnly tagDictionary As New Dictionary(Of Long, List(Of Tag))()
    Public ReadOnly Property ID As Long

    Public Sub New(row As DataRow)
        Me.ID = CLng(row.Item("ID"))
        If Not tagDictionary.ContainsKey(Me.ID) Then tagDictionary.Add(Me.ID, Nothing)
    End Sub

    Public ReadOnly Property Tags As List(Of Tag)
        Get
            Dim emptyTagIDs = tagDictionary.Where(Function(kvp) kvp.Value Is Nothing).Select(Function(kvp) kvp.Key)
            If emptyTagIDs.Contains(Me.ID) Then
                Dim d = getAllTagsWithIDs(emptyTagIDs)
                For Each kvp In d
                    tagDictionary(kvp.Key) = kvp.Value
                Next
            End If
            Return tagDictionary(Me.ID)
        End Get
    End Property

    Private Shared Function getAllTagsWithIDs(ids As IEnumerable(Of Long)) As Dictionary(Of Long, List(Of Tag))
        ' One query, giant result set
    End Function

End Class

这里是测试方式(用您的特定实现代替)

Dim dt As New DataTable()
Dim row As DataRow
row = dt.NewRow()
row("ID") = 1
Dim i1 = New Item(row)
row = dt.NewRow()
row("ID") = 2
Dim i2 = New Item(row)
row = dt.NewRow()
row("ID") = 3
Dim i3 = New Item(row)
Dim tags2 = i2.Tags ' at this point, all IDs are queried
row = dt.NewRow()
row("ID") = 4
Dim i4 = New Item(row)
Dim tags1 = i1.Tags ' no new query is performed because 1 was already queried
Dim tags4 = i4.Tags ' query is performed again on on new (ID = 4) items

优点是,只要访问当前标签,只要以前没有查询过当前标签,就可以再次查询所有以前未查询的ID。我认为这将完全按照您当前使用的方式工作(我想您已经在查询任何标签之前构造了所有项目)。但是,它还为您提供了更多的灵活性,可以创建更多项目,并仅在以后查询新标签。