FAQ
Here's an interesting situation I'm debugging now for Cayenne 1.1.
It seems to be related to CAY-213 "NullPointerException in
ContextCommit with locking". I suspect that it's true of 1.2 and
could very well be true for 3.0 as well, although I don't have that
handy to test with.

http://issues.apache.org/cayenne/browse/CAY-213

My testing seems to reveal that the same problem occurs when you set a
to-one relationship to null. Line 291 in removeToManyTarget() sets
the state of the previous to-one relationship object to MODIFIED, but
doesn't retain a snapshot for that object.

Here's some simple test code that shows the problem. And switching
the scalar setter with the relationship setter works around the
problem.

It seems to me that the the fix is to add

             dataContext.getObjectStore().retainSnapshot(this);

as was done for writeProperty().


     public void run() throws Exception
     {
         initCayenne("cayenne.xml");

         // Set up database
         createSchemaForObjEntityName(Configuration.getSharedConfiguration(),
"PotentialCustomer");
         DataContext dc = DataContext.createDataContext();

         // Set up test data
         PotentialCustomer pc =
(PotentialCustomer)dc.createAndRegisterNewObject(PotentialCustomer.class);
         Premise premise = (Premise)dc.createAndRegisterNewObject(Premise.class);
         pc.setToOneTarget("premise", premise, true);
         dc.commitChanges();

         // Force failure:
         pc.setToOneTarget("premise", null, true);
         premise.writeProperty("altitude", new Integer(0));

// On commitChanges(), no snapshot available for building locking
// java.lang.NullPointerException
// at org.objectstyle.cayenne.access.ContextCommit.appendOptimisticLockingAttributes(ContextCommit.java:564)

         dc.commitChanges();
     }


java.lang.NullPointerException
  at org.objectstyle.cayenne.access.ContextCommit.appendOptimisticLockingAttributes(ContextCommit.java:564)
  at org.objectstyle.cayenne.access.ContextCommit.prepareUpdateQueries(ContextCommit.java:426)
  at org.objectstyle.cayenne.access.ContextCommit.commit(ContextCommit.java:156)
  at org.objectstyle.cayenne.access.DataContext.commitChanges(DataContext.java:1266)
  at org.objectstyle.cayenne.access.DataContext.commitChanges(DataContext.java:1236)
  at com.gvea.cayenne.TestOptimisticLockingFailureOnSingleTargetNull.run(TestOptimisticLockingFailureOnSingleTargetNull.java:110)
  at com.gvea.cayenne.TestOptimisticLockingFailureOnSingleTargetNull.main(TestOptimisticLockingFailureOnSingleTargetNull.java:24)

Note that some of these line numbers may vary as my version of Cayenne
1.1 has local mods.

Search Discussions

  • Mike Kienenberger at Mar 27, 2008 at 8:31 pm
    Ok. I tried to do some testing on this, and as far as I can tell,
    it's only broken for 1.1, and not 1.2, 2.0, or 3.0.

    So I'm just going to patch it locally, and noting the patch in this thread:

    Index: E:/workspace311/cayenne-1.1.4/src/cayenne/java/org/objectstyle/cayenne/CayenneDataObject.java
    ===================================================================
    --- cayenne-1.1.4/src/cayenne/java/org/objectstyle/cayenne/CayenneDataObject.java (revision
    543577)
    +++ cayenne-1.1.4/src/cayenne/java/org/objectstyle/cayenne/CayenneDataObject.java (working
    copy)
    @@ -289,6 +289,7 @@
              relList.remove(value);
              if (persistenceState == PersistenceState.COMMITTED) {
                  persistenceState = PersistenceState.MODIFIED;
    + dataContext.getObjectStore().retainSnapshot(this);
              }

              if (value != null && setReverse) {



    On 3/27/08, Mike Kienenberger wrote:
    Here's an interesting situation I'm debugging now for Cayenne 1.1.
    It seems to be related to CAY-213 "NullPointerException in
    ContextCommit with locking". I suspect that it's true of 1.2 and
    could very well be true for 3.0 as well, although I don't have that
    handy to test with.

    http://issues.apache.org/cayenne/browse/CAY-213

    My testing seems to reveal that the same problem occurs when you set a
    to-one relationship to null. Line 291 in removeToManyTarget() sets
    the state of the previous to-one relationship object to MODIFIED, but
    doesn't retain a snapshot for that object.

    Here's some simple test code that shows the problem. And switching
    the scalar setter with the relationship setter works around the
    problem.

    It seems to me that the the fix is to add

    dataContext.getObjectStore().retainSnapshot(this);

    as was done for writeProperty().


    public void run() throws Exception
    {
    initCayenne("cayenne.xml");

    // Set up database
    createSchemaForObjEntityName(Configuration.getSharedConfiguration(),
    "PotentialCustomer");
    DataContext dc = DataContext.createDataContext();

    // Set up test data
    PotentialCustomer pc =
    (PotentialCustomer)dc.createAndRegisterNewObject(PotentialCustomer.class);
    Premise premise = (Premise)dc.createAndRegisterNewObject(Premise.class);
    pc.setToOneTarget("premise", premise, true);
    dc.commitChanges();

    // Force failure:
    pc.setToOneTarget("premise", null, true);
    premise.writeProperty("altitude", new Integer(0));

    // On commitChanges(), no snapshot available for building locking
    // java.lang.NullPointerException
    // at org.objectstyle.cayenne.access.ContextCommit.appendOptimisticLockingAttributes(ContextCommit.java:564)

    dc.commitChanges();
    }


    java.lang.NullPointerException
    at org.objectstyle.cayenne.access.ContextCommit.appendOptimisticLockingAttributes(ContextCommit.java:564)
    at org.objectstyle.cayenne.access.ContextCommit.prepareUpdateQueries(ContextCommit.java:426)
    at org.objectstyle.cayenne.access.ContextCommit.commit(ContextCommit.java:156)
    at org.objectstyle.cayenne.access.DataContext.commitChanges(DataContext.java:1266)
    at org.objectstyle.cayenne.access.DataContext.commitChanges(DataContext.java:1236)
    at com.gvea.cayenne.TestOptimisticLockingFailureOnSingleTargetNull.run(TestOptimisticLockingFailureOnSingleTargetNull.java:110)
    at com.gvea.cayenne.TestOptimisticLockingFailureOnSingleTargetNull.main(TestOptimisticLockingFailureOnSingleTargetNull.java:24)

    Note that some of these line numbers may vary as my version of Cayenne
    1.1 has local mods.
  • Mike Kienenberger at Sep 13, 2013 at 8:47 pm
    As I mentioned earlier, I'm upgrading my ancient Cayenne project from
    1.1 to 3.x, currently 3.0.2.

    I started by upgrading to 1.2 and 2.0, unfortunately hitting the old
    null-relationship-breaks-optimistic-locking error.

    http://mail-archives.apache.org/mod_mbox/cayenne-dev/200803.mbox/%3C8f985b960803271232s5018a5a9hbf0f731f82666e6a@mail.gmail.com%3E

    Since most everything else seemed to be working, and the the
    workaround I had for 1.1 wasn't possible in 1.2/2.0, I decided to skip
    ahead to 3.0 and hope it was fixed there, or that it'd be more
    relevant to fix there.

    But the same behavior I see in 1.2 and 2.0 still occurs in 3.0.2. For
    1.1, the fix was to retain a new snapshot when resolving faults, but
    the problem here seems to be slightly different.

    My model has a "User" object and a "PotentialCustomer" object. The
    PotentialCustomer is an optional one-to-one relationship with the
    User, where they both have the same primary key. In the past I have
    left the PotentialCustomer relationship as "Used for Locking",
    although I've set it both ways without changing the resulting error.

    Committing an unrelated attribute change to the "User" object when it
    has no corresponding "PotentialCustomer" object generates a "where
    USER_ID is null" clause.

    Writing a property change eventually generates an arcSnapshot for all
    to-one relationships, even if they are not marked for locking.
    org.apache.cayenne.access.ObjectDiff.java - line 114:

                     public boolean visitToOne(ToOneProperty property) {

                         // eagerly resolve optimistically locked relationships
                         Object target = lock ?
    property.readProperty(object) : property
                                 .readPropertyDirectly(object);

                         if (target instanceof Persistent) {
                             target = ((Persistent) target).getObjectId();
                         }
                         // else - null || Fault

                         arcSnapshot.put(property.getName(), target);
                         return true;
                     }

    The problem is that with a relationship which is optional, the target
    is going to be null. And later on, when we generate optimistic
    locking qualifiers in
    org.apache.cayenne.access.DataNodeSyncQualifierDescriptor, we store
    this null value as the matching value for the record's primary key.

    To me, part of the fix would seem to be to not do anything if we're
    not locking on this column. Why do we need to resolve a relationship
    or store a snapshot for a column not involved in optimistic locking?

    Second, even if this column is involved with optimistic locking, it
    should not be used as a replacement value for the modified object's
    primary key. It's probably a model error to specify a relationship
    based on the modified object's primary key as a locking column.
    However, I can correct this by removing the "Used for Locking" value.

    On Thu, Mar 27, 2008 at 3:32 PM, Mike Kienenberger wrote:
    Here's an interesting situation I'm debugging now for Cayenne 1.1.
    It seems to be related to CAY-213 "NullPointerException in
    ContextCommit with locking". I suspect that it's true of 1.2 and
    could very well be true for 3.0 as well, although I don't have that
    handy to test with.

    http://issues.apache.org/cayenne/browse/CAY-213

    My testing seems to reveal that the same problem occurs when you set a
    to-one relationship to null. Line 291 in removeToManyTarget() sets
    the state of the previous to-one relationship object to MODIFIED, but
    doesn't retain a snapshot for that object.

    Here's some simple test code that shows the problem. And switching
    the scalar setter with the relationship setter works around the
    problem.

    It seems to me that the the fix is to add

    dataContext.getObjectStore().retainSnapshot(this);

    as was done for writeProperty().


    public void run() throws Exception
    {
    initCayenne("cayenne.xml");

    // Set up database
    createSchemaForObjEntityName(Configuration.getSharedConfiguration(),
    "PotentialCustomer");
    DataContext dc = DataContext.createDataContext();

    // Set up test data
    PotentialCustomer pc =
    (PotentialCustomer)dc.createAndRegisterNewObject(PotentialCustomer.class);
    Premise premise = (Premise)dc.createAndRegisterNewObject(Premise.class);
    pc.setToOneTarget("premise", premise, true);
    dc.commitChanges();

    // Force failure:
    pc.setToOneTarget("premise", null, true);
    premise.writeProperty("altitude", new Integer(0));

    // On commitChanges(), no snapshot available for building locking
    // java.lang.NullPointerException
    // at org.objectstyle.cayenne.access.ContextCommit.appendOptimisticLockingAttributes(ContextCommit.java:564)

    dc.commitChanges();
    }


    java.lang.NullPointerException
    at org.objectstyle.cayenne.access.ContextCommit.appendOptimisticLockingAttributes(ContextCommit.java:564)
    at org.objectstyle.cayenne.access.ContextCommit.prepareUpdateQueries(ContextCommit.java:426)
    at org.objectstyle.cayenne.access.ContextCommit.commit(ContextCommit.java:156)
    at org.objectstyle.cayenne.access.DataContext.commitChanges(DataContext.java:1266)
    at org.objectstyle.cayenne.access.DataContext.commitChanges(DataContext.java:1236)
    at com.gvea.cayenne.TestOptimisticLockingFailureOnSingleTargetNull.run(TestOptimisticLockingFailureOnSingleTargetNull.java:110)
    at com.gvea.cayenne.TestOptimisticLockingFailureOnSingleTargetNull.main(TestOptimisticLockingFailureOnSingleTargetNull.java:24)

    Note that some of these line numbers may vary as my version of Cayenne
    1.1 has local mods.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupdev @
categoriescayenne
postedMar 27, '08 at 7:33p
activeSep 13, '13 at 8:47p
posts3
users1
websitecayenne.apache.org

1 user in discussion

Mike Kienenberger: 3 posts

People

Translate

site design / logo © 2021 Grokbase