IEnumerable中的延迟属性

问题描述 投票:1回答:1

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

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

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

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

当我有一个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属性是什么都没有

我已经混合并匹配这两种情况,因此如果没有调用它将反而回退并通过第一种情况下的机制获得它,但是这导致我回到第一种情况,其他开发人员将只允许惰性机制没有意识到SetTags存在或它的目的。

我想我的问题是,是否有一些模型或首选的方式来做我想做的事情,我不知道我可以实现两全其美?我很难解决这个问题,因为它很难解释。

希望这是有道理的,希望有一个解决方案,如果不是,我想我会坚持我所拥有的。

.net vb.net lazy-loading ienumerable
1个回答
1
投票

您可以使用静态成员自动化逻辑,同时隐藏类中的机制。使用静态对象使每个Item都知道其他Items,允许逻辑在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。我认为这将与您当前使用它完全一样(我猜您在查询任何标签之前已经构建了所有项目)。但它也为您提供了一些额外的灵活性来创建更多项目,并且稍后只查询新标签。

© www.soinside.com 2019 - 2024. All rights reserved.