You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Andrew Willerding <aw...@itsurcom.com> on 2019/01/22 16:06:44 UTC
How to get the changes to an object in PreUpdate?
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
Re: How to get the changes to an object in PreUpdate?
Posted by Andrew Willerding <aw...@itsurcom.com>.
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 <aw...@itsurcom.com> 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 <aw...@itsurcom.com>:
>>>>
>>>> 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
>>>>
>>>>
>>>>
Re: How to get the changes to an object in PreUpdate?
Posted by Andrus Adamchik <an...@objectstyle.org>.
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 <aw...@itsurcom.com> 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 <aw...@itsurcom.com>:
>>>
>>> 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
>>>
>>>
>>>
>>
Re: How to get the changes to an object in PreUpdate?
Posted by Andrew Willerding <aw...@itsurcom.com>.
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 <aw...@itsurcom.com>:
>>
>> 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
>>
>>
>>
>
Re: How to get the changes to an object in PreUpdate?
Posted by Maik Musall <ma...@selbstdenker.ag>.
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 <aw...@itsurcom.com>:
>
> 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
>
>
>