I am only about half-way through Eric's book so forgive me if this
question is answered later in the text...
I am implementing a Domain Model which has a datastore which can be
updated simultaneously by multiple users and does not support
transactions so at any time any piece of data previously fetched can
be updated without any notification. Based on this I am having a
hard time figuring out how often I should be going to the repository
to fetch data. I have provided a refresh method in my repositories
which takes a DomainObject and updates it, but I am unsure how to
approach the methods found in some of my DomainObjects which return
query from another repository. Do I cache the query, or each object
returned from the query or perhaps nothing at all? I want to make
sure that only one object of a given id exists in memory at a time.
I am familiar with Fowler's IdentityMap pattern but dont want to get
into the situation where I am loading the entire object graph into
memory.
Any suggestions?
Thanks,
JoshKnowles
I don't see how you can cache anything at all, then. Any caching
strategy would be randomized, at best. Is 100% data integrity not a
requirement?
JBRainsberger
Hi Josh,
You've identified at least three separate concerns here: cache staleness,
identity integrity in memory, and graph connectedness. It may be helpful to
discuss them separately to the extent possible. IdentityMap solves identity
integrity but need not imply graph connectedness or strong references to mapped
objects. Unless cache staleness doesn't hurt users too badly, you may not have
much choice but to always query - which may have performance implications. I
was confused by "how to approach the methods found in some of my DomainObjects
which return query from another repository" - can you elaborate?
Thanks,
RandyStafford
Yes 100% data integrity is a requirement, and I could go directly to the datastore upon every get/set, but I am running into problems because I rely on PropertyChangeEvents to notify the UI when things change, so I need to make sure that only once instance of a given DomainObject exists in memory for a given ID. If in one window the user does a query, then opens another window and does a similar query I need to make sure that all changes to the objects in the second window are mimicked to the objects in the first. My thought was to keep an IdentityMap and check this map for the existence of an object when loading a query, if it exists then I refresh it, if not then I load a new object. The problem is when do I clear this IdentityMap so it doesn't start to fill with all possible objects .
I would appreciate any suggestions if I appear to be approaching things drastically wrong.
JoshKnowles
<JavaAssumption>
Just implement your IdentityMap with java.lang.ref.SoftReferences or java.lang.ref.WeakReferences.
</JavaAssumption>
RandyStafford
Randy,
Let me see if I can elaborate a bit better:
I am modeling a network switch. This switch contains, among many things, ports and vlans. I currently have a repository for ports and a repository for vlans. Within my switch object I have two methods ports() and vlans() which go to the appropriate repositories and request all objects for the given switch. So I guess the switch object is the root aggregate(?) and provides a one-to-many relationship between all of its features such as ports and vlans which are also Entities.
JoshKnowles
josh,
from Fowler's Patterns of Enterprise Application Architecture:
* Optimistic Offline Lock (416) - add a version number to your objects. check
it and increment it on each update.
* Lazy Load (200) - load the object from datastore when the object is
accessed.
* Identity Map (195) - keep only a single reference to all objects.
if the probably of concurrent access is very high, then Pessimistic Offline
Lock may be more appropriate.
if strategically apply "Lazy Load", you will not load in the entire object
graph.
MarkRim
I think I understand. Your follow-on question was "Do I cache the query, or each object returned from the query or perhaps nothing at all?" I didn't understand *where* you were thinking of doing the caching - in the repository, in the switch object, in clients of the switch object, etc. Sounds like you're on the right track thinking of switch as an aggregate root and encoding clients to access switch subobjects through the switch.
To your scenario of two views open on the same model, and each needing to observe the other's changes to that model: I imagine you want those model objects in memory as long as the views are open/extant. If you let the views maintain strong references to the model objects, but use weak references in your IdentityMap, then I think you'll get the identity integrity you want, plus the memory consumption behavior you want.
Graph connectedness hasn't entered into the discussion yet, unless you use caching instance variables in the switch to avoid going to the repository on the 2nd through Nth requests. If you do that, then you need to be concerned about the strengths and lifetimes of references to the switch, and/or use soft reference -typed instance variables, etc.
RandyStafford
maybe is not the appropriate forum, but does anyone know how to implement optimistic lock with EJB CMP?
Thanks,
PabloSchor
Thanks! I will look into the WeakReference object that you suggested.
JoshKnowles
HowLongDoYouCacheObjectValues is mentioned on: ThreadView