Hi,

Yeah this is a familiar problem, which essentially comes down to the fact that 
while Cayenne has all the info for change tracking, the API to use it is 
somewhat complex. In Cayenne 3.1 we provide a better way (that we still need to 
document), based on lifecycle events and a few extensions in 
cayenne-lifecycle.jar. So here is how you might approach it:

1. Create annotation to tag the entities that require "last modified" update:

@Target( { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface LastModified {
}

2. Create listener that will process last modified updates for all objects. 
Configure it to only match the annotated entities:

public class LastModifiedListener {
        
        @PrePersist(entityAnnotations = LastModified.class)
        @PreUpdate(entityAnnotations = LastModified.class)
        void insertAudit(DataObject object) {
                
if(!ChangeSetFilter.preCommitChangeSet().getChanges(object).isEmpty()) {
                        object.writeProperty("lastModified", new Date());
                }
        }
}

3. On startup register the listener and ChangeSetFilter that will track object 
changes:

runtime.getDataDomain().getEntityResolver().getCallbackRegistry().addListener(new
 LastModifiedListener());
runtime.getDataDomain().addFilter(new ChangeSetFilter());


Now place @LastModified annotation on a subset of entity classes and it all 
should work. While this requires some setup, the benefit of this approach is 
that it is declarative, works the same way for any entity type, and does not 
require you to check your object state on commit explicitly.

Also if you need to tweak change analysis done between 
ChangeSetFilter/GenericChangeSet, feel free to write your own custom filter 
based on ChangeSetFilter example.

HTH,
Andrus

On Nov 21, 2012, at 11:02 PM, devnull2...@gmx.de wrote:

> Hi,
> 
> I'm working on web application with tapestry 5.3.6, tapestry5-cayenne 
> 0.5-SNAPSHOT and cayenne 3.1B1.
> 
> I've got several pages with forms for a user to edit something. Some
> entities/objects have a field called lastmodified, so before I call
> context.commitChanges() I set a new timestamp for lastmodified. Before I do 
> that I'd like to find out if there really are changes. Otherwise, if a user 
> doesn't actually edit anything and just clicks on save, I'd set a new
> lastmodified date and that timestamp would be the only value that really is
> different than before.
> 
> I can't use context.hasChanges() because it is always true. Tapestry calls 
> setXyz() for every field of a bean (at least if I use BeaneditForm). 
> 
> So I'm wondering if I should not use BeanEditForm at all and instead use 
> forms with input fields that aren't bound to the object's values and handle 
> everything myself? For example use a String name for a form input field and 
> then check the user's input, compare the value to myItem.getName() and only 
> if it's different call myItem.setName(name)? Then I could check 
> context.hasChanges I guess.
> 
> I googled around some and found a thread from 2009 with a similar problem: 
> Any way to check if object has really changed?
> http://mail-archives.apache.org/mod_mbox/cayenne-user/200903.mbox/%3c3219fff70903240659p2196e7d2h7c9d020cc5063...@mail.gmail.com%3E
> The thread starter also posted some code to check for changes.
> Should I rather use this method?
> What would be "good practice"?
> 
> I also don't understand all of the code from that thread I mentioned. 
> 
> private boolean hasChanged(CayenneDataObject cdo) {
>    ...
>    if (cdo.getPersistenceState() != PersistenceState.MODIFIED) {
>        return true;
>    }
>    ...
> }
> 
> It checks if PersistenceState is MODIFIED and if it is not, then it returns 
> true. But what if PersistenceState is COMMITTED or HOLLOW, this doesn't 
> necessarily mean there are changes, does it?
> 
> Further down the relationships are checked:
> 
> for (ObjRelationship rel : entity.getRelationships()) {
>    if (!rel.isFlattened() && !rel.isToMany()) {
>        ...
>    }
> }
> 
> but there is no else for the if, so toMany relationships are ignored. How 
> could I check if a toMany relationship of an entity has changes? In this  
> case I sometimes should set a new lastmodified timestamp, too.
> 
> Cheers,
> -Bjello
> 
> 
> 
> 
> 
> 

Reply via email to