Hi all,
That's exactly what I did, except for the method names :-). Just
instead of having a static method somewhere, I've implemented willCommit
in the super class and called validate(ValidationResult), if there's an
error, I tried to throw an exception with the ValidationResult in it
(I'll have a look at Validator and ValidationInfo). The draw back here
is that ValidationResult will not contain *every* validation error, just
the errors found in the first class that breaks.
The static method does what I need for now, I just need to remember
to call it and I tend to forget these things :-)
But anyway, I believe Cayenne should support some kind of
validation. What's the best way to do it? I don't know. I agree with the
suggestion of copying this static method to the beginning of commit,
including delete on it (an object may decide it shouldn't be deleted).
Also, it would be very nice if the modeller generated some of the
validation, like field length, nulls, etc.
As for return vs. exception, I vote for validateForSave() to return
it, so we can collect all errors and commit() to throw an exception,
because the code that handles the errors might not be the same that
commits the context. The exception breaks the execution and back-tracks
to the right place, it would be a pain to do the same with return.
Once we decide how we're going to do it, I'm willing to implement it
for beer :-)
Thanks,
Fabricio.
Andrus Adamchik wrote:
>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:
>
>http://objectstyle.org/cayenne/api/cayenne/org/objectstyle/cayenne/project/validator/ValidationInfo.html
>
>
>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
>
>
>
>
>
-- Fabricio Voznika Senior Programmer/Analyst Administrative Computing Dartmouth College Phone: 603-646-2007
This archive was generated by hypermail 2.0.0 : Tue Jul 29 2003 - 11:15:54 EDT