Re: PersistenceState relation to property changes

From: Sean Tan (sabrebox2000-cod..ahoo.com.sg)
Date: Fri Aug 26 2005 - 11:55:43 EDT

  • Next message: Mike Kienenberger: "Re: PersistenceState relation to property changes"

    Hmm, but in doing so, the PersistenceState will become MODIFIED whenever
    a single setter is invoked... I'm not sure whether this is the original
    intention, but I felt it will be more intuitive that it reflects an
    actual change in value.

    Did I again missed out something that will break the code?

    Just a side note, I have noticed that DataContext.commitChanges() relies
    on ObjectStore.hasChanges() which checks for the the
    PersistenceState.MODIFIED. When a DataObject is in this state, there
    will be iteration to check for modified fields. Thus perhaps by making
    the PersistenceState to be MODIFIED only when there is an actual change
    in value could constitue a minor improvement in speed when there is a
    large number of unchanged DataObject with PersistenceState.MODIFIED?
    This is just a wild guess since I have not done any profiling in Cayenne
    before.

    Mike Kienenberger wrote:

    >If it were me, I'd still add a check in validateForSave() to make sure
    >that the current valuees being committed were different from the
    >cached snapshot, and I wouldn't try to modify the persistence state in
    >writeProperty.
    >
    >
    >
    >On 8/26/05, Sean Tan <sabrebox2000-cod..ahoo.com.sg> wrote:
    >
    >
    >>Thanks alot for pointing that out Mike! I missed out the problem.
    >>
    >>I have taken your suggestion and Andrus to implement my solution.
    >>
    >>I have included the code here for completeness sake of the discussion.
    >>-----
    >>public class MyCayenneDataObject extends
    >>org.objectstyle.cayenne.CayenneDataObject {
    >>
    >> public void writeProperty(String propName, Object val) {
    >> resolveFault();
    >>
    >> // 1. retain object snapshot to allow clean changes tracking
    >> // 2. change object state
    >> if (persistenceState == PersistenceState.COMMITTED) {
    >> DataRow committedSnapshot =
    >>dataContext.getObjectStore().getCachedSnapshot(getObjectId());
    >> boolean modified = false;
    >> if (committedSnapshot == null) {
    >> modified = true;
    >> } else {
    >> Object oldValue = committedSnapshot.get(propName);
    >> modified = !Util.nullSafeEquals(oldValue, val);
    >> }
    >> if (modified) {
    >> persistenceState = PersistenceState.MODIFIED;
    >> dataContext.getObjectStore().retainSnapshot(this);
    >> }
    >> }
    >> // else....
    >> // other persistence states can't be changed to MODIFIED
    >>
    >> writePropertyDirectly(propName, val);
    >> }
    >>
    >>}
    >>-----
    >> protected void validateForSave(ValidationResult validationResult) {
    >> setTimestamp(new Date(System.currentTimeMillis()));
    >> super.validateForSave(validationResult);
    >> }
    >>-----
    >>
    >>Sean
    >>
    >>Mike Kienenberger wrote:
    >>
    >>
    >>
    >>>The problem with doing it with writeProperty() is that it won't detect
    >>>differences in this situation:
    >>>
    >>>obj.getField() == 1
    >>>
    >>>obj.setField(0);
    >>>obj.setField(1);
    >>>obj.getDataContext().commit;
    >>>
    >>>However, as Andrus states, if you want to do this, it's trivial to
    >>>handle this in a base DataObject superclass.
    >>>
    >>>(In fact, I override writeObject in a base DataObject superclass to
    >>>change empty strings to null since Oracle doesn't handle empty
    >>>strings.
    >>>
    >>>If you're willing to dig into the advanced parts of Cayenne a little
    >>>more, you can use the same logic that Cayenne uses for determining
    >>>which objects have changed fields in validate*.
    >>>
    >>>You'd just compare the current value snapshots with the original
    >>>object snapshots.
    >>>
    >>>On 8/26/05, Sean Tan <sabrebox2000-cod..ahoo.com.sg> wrote:
    >>>
    >>>
    >>>
    >>>
    >>>>Thanks a lot for very quick reply Andrus! =)
    >>>>Hmm.... I tried your suggestion but notice the follow things:
    >>>>1. Cayenne relies on DataContext.hasChanges() to know whether there is
    >>>>any real modifications. But this only allows Cayenne to know whether
    >>>>there are any modifications within the DataContext, not based on
    >>>>individual DataObjects.
    >>>>2. Due to the above, once there is a single modified DataObject within
    >>>>the DataContext, the validate* methods will be called for all
    >>>>DataObjects marked modified.
    >>>>
    >>>>As such, I think your suggestion does not work.
    >>>>
    >>>>I'm not sure how useful will it be to the rest of the users, but I guess
    >>>>having the PersistenceState.MODIFIED to reflect real modifications are
    >>>>intuitive and useful in most cases. Or perhaps we can have an option to
    >>>>turn it On/Off....
    >>>>
    >>>>On the same line, perhaps out-of-the-box Cayenne could support the use
    >>>>of fields like TimeStamp, as it would help alot in users who are
    >>>>re-engineering from existing DB systems which relies on this feature.
    >>>>
    >>>>--
    >>>>Sean
    >>>>
    >>>>Andrus Adamchik wrote:
    >>>>
    >>>>
    >>>>
    >>>>
    >>>>
    >>>>>Hi there,
    >>>>>
    >>>>>Your solution will work and you can put your overridden
    >>>>>"writeProperty" in your own custom superclass of DataObjects thus
    >>>>>changing default Cayenne behavior.
    >>>>>
    >>>>>Here is another solution however - override "validateForSave" to add
    >>>>>your timestamp logic:
    >>>>>
    >>>>>http://objectstyle.org/cayenne/userguide/dataobjects/validation.html
    >>>>>
    >>>>>See, even if an object is marked as modified on "setXYZ" call when
    >>>>>there was no real modification, this fact will be detected by Cayenne
    >>>>>later on commit, and the object will not be committed, and its
    >>>>>validate* methods won't be called.
    >>>>>
    >>>>>Hope this helps.
    >>>>>
    >>>>>Andrus
    >>>>>
    >>>>>On Aug 26, 2005, at 2:03 PM, Sean Tan wrote:
    >>>>>
    >>>>>
    >>>>>
    >>>>>
    >>>>>
    >>>>>>I'm attempting to use Cayenne v1.1.2 with the idea of having a field
    >>>>>>that mimics the behavior of MySql's TimeStamp dbtype.
    >>>>>>
    >>>>>>The timestamp will only update if at least a change is detected in the
    >>>>>>rest of the columns.
    >>>>>>
    >>>>>>I'm trying to rely on the PersistenceState of CayenneDataObject but I
    >>>>>>realized that the PersistenceState is set to Modified even when the new
    >>>>>>value being introduced is the same as the old value. This poses a
    >>>>>>problem, especially in the context of webframeworks like Tapestry which
    >>>>>>all bounded fields will be updated, meaning the writeProperty(String
    >>>>>>propName, Object val) of the CayenneDataObject will always be
    >>>>>>called....
    >>>>>>PersistenceState being set to Modified although no change is made.
    >>>>>>
    >>>>>>One usage scenario is when you create a HTML table of records which
    >>>>>>allows the user to change the records inline, and click on a update
    >>>>>>button.
    >>>>>>
    >>>>>>Thus, I'm proposing that perhaps the writeProperty method could be
    >>>>>>adjusted to do additional check as below to suit this purpose.
    >>>>>>----
    >>>>>>public void writeProperty(String propName, Object val) {
    >>>>>> resolveFault();
    >>>>>>
    >>>>>> // 1. retain object snapshot to allow clean changes tracking
    >>>>>> // 2. change object state
    >>>>>> Object oldVal = readPropertyDirectly(propName);
    >>>>>> if (persistenceState == PersistenceState.COMMITTED &&
    >>>>>>oldVal.equals(val) == false) {
    >>>>>> persistenceState = PersistenceState.MODIFIED;
    >>>>>> dataContext.getObjectStore().retainSnapshot(this);
    >>>>>> }
    >>>>>> // else....
    >>>>>> // other persistence states can't be changed to MODIFIED
    >>>>>>
    >>>>>> writePropertyDirectly(propName, val);
    >>>>>> }
    >>>>>>-----
    >>>>>>
    >>>>>>Or am I missing out a better way to do this?
    >>>>>>
    >>>>>>--
    >>>>>>Sean Tan
    >>>>>>
    >>>>>>
    >>>>>>
    >>>>>>
    >>>>>
    >>>>>
    >>>>>
    >>>>Send instant messages to your online friends http://asia.messenger.yahoo.com
    >>>>
    >>>>
    >>>>
    >>>>
    >>>>
    >>>>
    >>>
    >>>
    >>>
    >>Send instant messages to your online friends http://asia.messenger.yahoo.com
    >>
    >>
    >>
    >>
    >
    >
    >
    Send instant messages to your online friends http://asia.messenger.yahoo.com



    This archive was generated by hypermail 2.0.0 : Fri Aug 26 2005 - 11:56:05 EDT