cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrus Adamchik <and...@objectstyle.org>
Subject Re: check for changes before commit
Date Thu, 22 Nov 2012 06:40:39 GMT
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, devnull2000@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/%3C3219fff70903240659p2196e7d2h7c9d020cc50635fa@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
> 
> 
> 
> 
> 
> 


Mime
View raw message