Re: PersistenceState relation to property changes

From: Mike Kienenberger (mkienen..mail.com)
Date: Fri Aug 26 2005 - 12:02:04 EDT

  • Next message: Sean Tan: "`"

    I don't really know the answer to your questions. My uncertainty is
    part of the reason I'd avoid changing the state.

    On the other hand, you might be fixing a bug or at least performance
    issue in the code :)

    On 8/26/05, Sean Tan <sabrebox2000-cod..ahoo.com.sg> wrote:
    > 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 - 12:02:06 EDT