首先道歉,如果应该在代码审查而不是在这里。我发现这里只是显示伪代码。
我有一个从数据库中加载的对象,该对象又具有从数据库中获取的惰性加载属性。
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上搜索这个问题,因为很难解释。
希望这是有道理的,希望有解决方案,如果没有,我想我会坚持下去。
答案 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。我认为这将完全按照您当前使用的方式工作(我想您已经在查询任何标签之前构造了所有项目)。但是,它还为您提供了更多的灵活性,可以创建更多项目,并仅在以后查询新标签。