There is a big improvement on post-update change capturing API 
("cayenne-commitlog" module [1]). However pre-update does require manual 
inspection of the object vs. saved state.

Andrus

[1] https://cayenne.apache.org/docs/4.0/cayenne-guide/#ext-commit-log

> On Jan 22, 2019, at 4:42 PM, Andrew Willerding <[email protected]> 
> wrote:
> 
> Thank you Maik.
> 
> I was hoping for something much simpler than this and that's baked into 
> Cayenne.
> 
> 
> On 2019-01-22 11:19 a.m., Maik Musall wrote:
>> Hi Andrew,
>> 
>> I did it like this in a DataDomainListener:
>> 
>>      @PreUpdate( { CayenneDataObject.class } )
>>      public void handleBeforeUpdateHook( CayenneDataObject object ) {
>>              if( object instanceof BeforeSaveHook ) {
>>                      ((BeforeSaveHook)object).beforeSaveAction();
>>              }
>>      }
>> 
>> and then have BeforeSaveHook be an interface, and then implementing 
>> beforeSaveAction in the DataObject classes. To get the actual changes, I 
>> also didn't find anything handy, and ended up doing it like this (in my 
>> custom DataObject subclass):
>> 
>>      public Map<String,ValueDifference<Object>> changedAttributes() {
>>              Set<String> attributeKeys = new HashSet<>( attributeKeys() );
>>              Map<String,Object> dataRow = oc().getObjectStore().getSnapshot( 
>> getObjectId() );
>>              
>>              if( dataRow == null ) { // newly inserted object
>>                      dataRow = new HashMap<>();
>>                      for( String key : attributeKeys ) {
>>                              dataRow.put( key, null );
>>                      }
>>              }
>>              
>>              Map<String,Object> committedValues = new HashMap<>();
>>              Map<String,Object> uncommittedValues = new HashMap<>();
>>              for( String key : dataRow.keySet() ) {
>>                      if( !attributeKeys.contains( key ) ) continue;
>>                      committedValues.put( key, dataRow.get( key ) );
>>                      Object uncommittedValue = readPropertyDirectly( key );
>>                      uncommittedValues.put( key, uncommittedValue );
>>              }
>>              
>>              MapDifference<String,Object> difference = Maps.difference( 
>> committedValues, uncommittedValues );
>>              Map<String,ValueDifference<Object>> entriesDiffering = 
>> difference.entriesDiffering();    // assuming the all keys will always be 
>> present in both
>>              return entriesDiffering;
>>      }
>> 
>> 
>> (where ValueDifference and MapDifference are Guava classes). Hope it helps, 
>> perhaps someone else has a better solution.
>> 
>> Maik
>> 
>> 
>> 
>>> Am 22.01.2019 um 17:06 schrieb Andrew Willerding <[email protected]>:
>>> 
>>> I can't seem to find documentation, or better yet some examples for 4.0 or 
>>> 4.1 that explains how to check for either a single property change or how 
>>> to get a list of the property changes in an onPreUpdate callback. Unless 
>>> I'm missing something obvious (entirely likely ;-) ) the Lifecycle events 
>>> documentation doesn't seem to mention any way to do this.  Is this 
>>> something that I need to manually track in the application?
>>> 
>>> Also, what should I do if I want to reject the changes inside of an 
>>> onPreUpdate callback?  Do I need to do an explicit rollback or simply throw 
>>> a CayenneRuntimeException of some sort?  I'm guessing it's an explicit 
>>> rollback.
>>> 
>>> Thanks,
>>> 
>>> Andrew
>>> 
>>> 
>>> 
>> 

Reply via email to