Hi Richard, That's similar to what I was suggesting, but it sounds like you ran into a problem first. That's why I was saying just prevent it in the Modeler and we can document how to work around it.
Thanks, mrg On Wed, Oct 19, 2011 at 10:28 AM, Richard Frovarp <[email protected]> wrote: > On 10/19/2011 02:02 AM, Andrus Adamchik wrote: >> >> Just coming of a few months (!) of low intensity debugging of a single >> problem that looked as if Cayenne resets a non-null to-one relationship to >> null. The FK would be not null in the DB, but all instances of a given >> object across all DataContexts in a given app would return null for that one >> relationship. Turned out this wasn't an obscure race condition, but rather >> the following scenario: >> >> 1. Assume Artist and Painting with painting having to one relationship >> called "artist", but also an ObjAttribute called "artistId" >> 2. For an existing Artist you may create a new painting, call "setArtist", >> but don't set the "artistId" attribute explicitly. >> 3. Commit - that creates a valid record with non-null PAINTING.ARTIST_ID >> in the db, but the object snapshot stored in DataRowStore suddenly has NULL >> for "ARTIST_ID" key. >> 4. From here all DataContexts that fault this painting from the shared >> cache will have NULL "artist" relationship, even though it is not null in >> the DB. >> >> The actual behavior during (3 - commit) I think is less deterministic and >> depends on the relative order of traversal of entity properties in the >> ClassDescriptor. So theoretically there may have been a reverse situation >> when NULL was saved to the DB, but not-null value remained in the snapshot. >> In any event it is extremely confusing. >> >> If we take a broader look at this problem, it is a case of redundant >> mapping (something in the DB layer is mapped multiple times in the object >> layer). There can be other cases with yet unknown sets of problems (e.g. >> multiple ObjRelationships over the same DbRelationship; flattened >> relationships, with a matching set of 1-step relationships; etc). >> >> We only have a single case where redundant mapping is handled correctly >> and consistently - exposed PK (meaningful or not) . Even if the exposed PK >> is generated by Cayenne, we have a mechanism to update object property. So >> this is a case when we do it right, and don't compromise on user choices of >> mapping scenarios. >> >> In case of exposed FK we have 2 options - (1) just add a Modeler >> validation to discourage this type of mapping (quick and easy) and (2) >> actually analyze the above and other possible scenarios when we need to >> synchronize relationship and attribute and write code to do that. #2 can be >> done as a post-commit pass over the objects to sync redundant mappings... >> Just not clear which one of the redundant mappings should be used to sync >> the others... >> >> Thoughts? > > I've ran into the problem myself when using non-synthetic keys. A warning in > the modeler would be useful, but I wouldn't prohibit the behavior. The work > around for my code was something like this: > > public class Painting { > @Override > public void setArtist(Artist artist) { > super.setArtist(artist); > this.setArtistId(artist.getId()); > } > } >
