After some more Googling, I found this ...
https://stackoverflow.com/questions/9899873/getting-a-fresh-data-object-in-apache-cayenne
...and modified my onPreUpdate to look like this...
@Override
protected void onPreUpdate() {
ContactType old =
ClientBaseAdmin.getTempObjectContext().localObject(this); //
getTempObjectContext gets a new ObjectContext different from the current
objects.
System.out.println("******Old=" + old.getDefaultAdminLevel() + ",New=" +
getDefaultAdminLevel());
if (getDefaultAdminLevel() < old.getDefaultAdminLevel()) {
throw new CayenneRuntimeException("Cannot create promote
ContactType to a higher authority without emptying the group:";
}
}
... and generated the expected output of ...
******Old=5,New=2
Relative Simplicity and Success that I can live with although perhaps
something like this.DEFAULT_ADMIN_LEVEL.getPreUpdateValue() would be
even simpler if it would be possible to implement within Cayenne. ;-)
On 2019-01-22 4:48 p.m., Andrus Adamchik wrote:
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