BTW, note that JPA "merge" returns a merged object, so it is exactly
like "localObject" in that it locates a copy of an object local to
the context.
Andrus
On Oct 16, 2007, at 10:02 AM, Andrus Adamchik wrote:
> Hi Kevin,
>
> Relating (as in "creating a direct reference in a Java sense") two
> objects belonging to two distinct contexts breaks fundamental
> Cayenne design, most notably assumptions about uniquing and
> transaction boundaries. I am -1 on that until somebody persuades me
> that this is a good idea and explains how to avoid messing up
> existing assumptions. (FWIW there is a workaround - referencing a
> peer of a given object in another context via 'localObject').
>
>
> On the other hand the inability to relate two TRANSIENT objects
> (i.e. objects without a context) is indeed a shortcuming. Here is
> one way how it might work (following the JPA patterns) :
>
> When such relationship is established, we would not attempt to
> create a reverse relationship (something that would require an
> EntityResolver to be present). We just create it one-way. So a user
> can build an object graph of an arbitrary size without a context
> and then at some point do one of the following with it:
>
> * "ObjectContext.registerNewObject(..)" (existing; equivalent to
> JPA "persist" method)
> * "ObjectContext.aNewMethod(..)" (does not exist yet; equivalent to
> JPA "merge" method and somewhat of an equivalent of a "localObject"
> method).
>
> Both would traverse a graph of transient objects (since they are
> not persistent yet, the graph is assumed to be finite and will not
> trigger sucking the entire DB in memory), attach them to the
> context and connect missing reverse relationships. The difference
> is that in the first case we'd assume that the objects are not yet
> persistent, while in a second case we'd attempt to match them
> against existing DB rows. (a typical use of a second case would be
> receiving XML-serialized stream of objects corresponding to the
> existing data).
>
>
> But you have something different in mind? Could you elaborate on
> the use cases?
>
> Thanks
> Andrus
>
>
> On Oct 16, 2007, at 1:25 AM, Kevin Menard wrote:
>> So, if there is one thing that drives me nuts about Cayenne, it's
>> managing
>> ObjectContexts. In particular, you cannot relate two Persistent
>> objects
>> without first putting them into an ObjectContext. If one is
>> committed and
>> the other is not, you can have them in different contexts, but for
>> newly
>> created objects, this is a major pain in the neck.
>>
>> Since I've been complaining about it for probably close to three
>> years now,
>> I'd like to finally do something about it.
>>
>> Here are my rough notes from the airport:
>>
>> OK Cases:
>>
>> - Objects in same context
>> - Objects in different contexts, but objects are committed already
>>
>> Don't work, but should:
>>
>> - Objects in null contexts
>> - Objects in different contexts, but same data maps and domains
>>
>> Very hard to say, probably okay if don't work:
>>
>> - Objects in different contexts, contexts have different data maps
>> - Objects in different contexts, contexts have different data domains
>>
>>
>> As I started actually digging into the code, I ran into a lot of
>> NPE issues
>> trying to associate two Persistent objects with no context with
>> one another.
>> In an attempt to prevent adding special null-logic handling, I
>> thought about
>> applying the Null Object pattern to the problem. The basic idea
>> is rather
>> than use null as the default objectContext for CDO, use an
>> instance of
>> DelayedContext. The problem here is having objects in different
>> contexts.
>> So, it appears by fixing one, you can essentially fix the other.
>>
>> To address the latter, I was looking to have a Set of
>> ObjectContexts stored
>> in either BaseContext or DataContext. When willConnect() is
>> called, you'd
>> have something like the following:
>>
>> else if (this.getObjectContext().getEntityResolver() ==
>> object.getObjectContext().getEntityResolver()) {
>> ((DataContext)
>> this.getObjectContext()).addContextToMergeWith
>> (object.getObjectContext());
>> ((DataContext)
>> object.getObjectContext()).addContextToMergeWith
>> (this.getObjectContext());
>> }
>> else {
>> throw new CayenneRuntimeException(
>> "Cannot set object as destination of
>> relationship "
>> + relationshipName
>> + " because it is in a different
>> DataMap or
>> DataDomain.");
>> }
>>
>> (Casts are just an artifact of me screwing around).
>>
>> What I'm thinking would happen is that when commitChanges() is
>> called, the
>> set of contexts to be merged with will be iterated and any changes
>> applied
>> to the current object store / object store graph diff. The
>> relationship is
>> bidirectional so that the user can initiate the commit from any
>> object
>> registered with any context.
>>
>> Here is about where I lose it. I'm not as well-versed in the
>> internal
>> going-ons of Cayenne as I would like to be. It appears Cayenne
>> goes to
>> great efforts to essentially cache the graph manipulations so as
>> to avoid a
>> full traversal. I really don't know, though.
>>
>> Caching ordering of operations could make this tricky, but in
>> principal
>> should be wholly doable.
>>
>> If anyone has any thoughts on this or can fill in any missing
>> pieces, I'd
>> appreciate it. This is really something I'd like to see fixed
>> sooner rather
>> than later. I think it may be a requisite for JPA compliance as
>> well.
>>
>> --
>> Kevin
>>
>>
>
>
This archive was generated by hypermail 2.0.0 : Tue Oct 16 2007 - 03:07:42 EDT