首先道歉,如果这应该是代码审查而不是在这里。我在这里想,因为我只显示伪代码。
我有一个从数据库加载的对象,该数据库又具有从数据库中获取的延迟加载属性。
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存在或它的目的。
我想我的问题是,是否有一些模型或首选的方式来做我想做的事情,我不知道我可以实现两全其美?我很难解决这个问题,因为它很难解释。
希望这是有道理的,希望有一个解决方案,如果不是,我想我会坚持我所拥有的。
您可以使用静态成员自动化逻辑,同时隐藏类中的机制。使用静态对象使每个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。我认为这将与您当前使用它完全一样(我猜您在查询任何标签之前已经构建了所有项目)。但它也为您提供了一些额外的灵活性来创建更多项目,并且稍后只查询新标签。