Problem
We have a complex domain model. To avoid performance issues, most of the list (generated from domain objects) are cached. Everything works well until the first domain object changes. All depending list in the cache must be refreshed - the question is: how?
Example
- Domain object: House
- Action: Name of a house has been changed
- Effect: all list (containts house names) are out-of-date, refresh needed
Solutions
No doubt, there is a very easy way: after saving a domain object, we refresh all list from code manually.
Pseudo c开发者_开发百科ode
repository.Save(save);
cacheManager.Invalidate("HouseList");
cacheManager.Invalidate("OrderedHouseList");
cacheManager.Invalidate("HousecombinedWithResidentsList");
...
So the problem is: we have to refresh everything manually. I'm looking for better solutions, let's say:
- Aspect oriented way w/ PostSharp or Windsor
- Observer or event based technique
- CQRS it's about separating queries and commands, but this conception is maybe too much.
Any idea or experience?
The answer to this question is complex because your requirements are unclear. Can data be stale? If so, how long?
Based on the limited information in your post, I would suggest the "cached" views merely being a query over the real data. The queries themselves could periodically refresh their cached results given some interval.
I'd say that, if your insert / update / delete modifies the contents of one of those lists, you should requery the list. I've got some cached datatables in my app, and I use a collection of the structure below to maintain them. This way, it's easy to clear the entire cache, and when I ask for a particular datatable I check to see if one exists in the cache which is not expired.
Protected Structure CachedDT
#Region "Local Variables"
Public TheDT As DataTable
Public TheExpirationTime As DateTime
Public TheUniqueIdentifier As String
#End Region 'Local Variables
End Structure
Protected cCachedDTs As Dictionary(Of String, CachedDT) = New Dictionary(Of String, CachedDT)
These live in my base class for objects which query databases. An example of using the cached datatables is:
<System.Diagnostics.DebuggerStepThrough> _
Public Overrides Function GetPermissionsSystem(ByVal SystemUserName As String) As DataTable
Try
Dim oCmd As New SqlCommand
Dim aDpt As New SqlDataAdapter
Dim aDst As New DataSet
Dim theCached As CachedDT
Dim theCacheName As String = "GetPermissionsSystem|" & SystemUserName
If cCachedDTs.ContainsKey(theCacheName) Then
theCached = cCachedDTs.Item(theCacheName)
If theCached.TheExpirationTime < DateTime.Now Then
cCachedDTs.Remove(theCacheName)
Else
Return theCached.TheDT
End If
End If
With oCmd
.Connection = MyBase.Conn
.CommandType = CommandType.StoredProcedure
.CommandTimeout = MyBase.TimeoutShort
.CommandText = Invoicing.GetPermissionsSystem
.Parameters.Add(GP("@SystemUserName", SystemUserName))
End With
aDpt.SelectCommand = oCmd
aDpt.Fill(aDst)
theCached = New CachedDT
With theCached
.TheUniqueIdentifier = theCacheName
.TheExpirationTime = DateTime.Now.AddSeconds(10)
.TheDT = aDst.Tables(0)
End With
cCachedDTs.Add(theCached.TheUniqueIdentifier, theCached)
Return aDst.Tables(0)
Catch sqlex As SqlException
MyBase.HandelEX(sqlex)
Catch ex As Exception
MyBase.HandleEX(ex)
Finally
MyBase.CloseConn()
End Try
End Function
In the above example, the function checks the cache to see whether an appropriate object exists. If it does, that gets returned rather than hitting the database again. At the end, the fresh object is added to the cache.
All you'd have to do would be to provide some means of removing a particular list from the cache. Then, when you do an insert / update / delete, make sure you clear the appropriate item.
精彩评论