Hi Holger, Fabricio,
Fabricio Voznika wrote:
>> How are you guys doing validation in your objects using cayenne?
>
> Uhmm.. *looking at floor*..good question! :-)
> There's not much (translation: almost nothing) in place for this right
> now. The event stuff is there and works but it's not fully used yet.
Before this is made a standard feature, validation can be easily
implemented in a way external to Cayenne. I'll share some ideas below.
>> The way I tried to do is to make my objects implement
>> DataObjectTransactionEventListener.willCommit(DataContextEvent) and do
>> all the checks there. But I haven't found a way to abort the commit
>> from there. If I throw an exception, it just get logged (see
>> Invocation.fire(Object[])) if I call DataContext.rollbackChanges() it
>
> Logging and subsequently ignoring any exceptions during event posting
> was simply the first thing that came to my mind because I definitely
> didn't want to abort the event loop just because one receiver bombed.
> Handling the greater meaning of the exception is not the Invocation's
> concern anyway, and the whole event machinery is meant to be as generic
> as possible.
Well, the way events are designed right now, they shouldn't be used for
validation at all. I mean, there is a difference between "notification"
and "delegation", even though in this case (each object validates itself)
semantics is similar. So basically instead of forcing valdiation on event
listeners, and allowing them to alter the flow, validation can work
outside of the event dispatch.
>
> I think your best bet (for now) will be to manually check objects right
> after modification. We definitely need a semi- (if not fully-)automagic
> strategy for that before 1.0, but unfortunately there is no 'definite'
> way to implement it since it often mixes business rules (model),
> transaction logic (model/controller) and (in a web app) web application
> state handling (controller). Even a manual way to abort 'the current
> transaction' (whatever that is ;) might be a good first remedy, but
> we'll need to discuss this with Andrus when he's back.
For now I suggest doing something like this (and maybe contributing this
to Cayenne if you feel like it ;-))
1. Use persistent objects inheritance hierarchy like:
MyObject extends _MyObject extends MyCayenneObject extends
CayenneDataObject (modeler should support that)
2. Implement a method like "MyCayenneObject.validateForSave(DataContext)"
to do common validation on "this" - nulls, max width, etc. dynamically
using DataMap to get the metadata. On failure throw an exception, or
return a validation object similar to this:
http://objectstyle.org/cayenne/api/cayenne/org/objectstyle/cayenne/project/validator/Validator.html
that contains a list of these:
3. Optionally override validateForSave in all variations of MyObject to do
business-specific validation (and calling super).
4. Implement a static method somewhere (e.g. in MyCayenneObject) like:
public static void commitChanges(DataContext ctxt) {
Collection modified = ctxt.modifiedObjects();
// call validateForSave on each one...
Collection newObjects = ctxt.newObjects();
// call validate for save on each one
// not sure if we need to validate deleted?
// do whatever needed if errors are found
// ....
// finally - commit if no errors
ctxt.commitChanges();
}
This is very generic, uses only Cayenne public API and shouldn't be too
hard to write (and in the futre plug into Cayenne core). There are few
details up for discussion, like "throw an exception vs. return a
validation object", or do both, etc...)
What d'ya think?
Andrus
This archive was generated by hypermail 2.0.0 : Tue Jul 29 2003 - 10:04:15 EDT