blob: c50b27ad2a464467454fd05a3e0b8d0699c770be [file] [log] [blame]
Title: DataObject Validation
<P>DataObject implements a set of methods to validate its state. DataContext calls these methods before performing a commit. If validation fails, commit is aborted with ValidationException. There are a few clear benefits of validating DataObjects at the application level before committing them to the database:</P>
<UL>
<LI>Cayenne can leverage ORM metadata (DataMap) to check for many standard error conditions.</LI>
<LI>Custom validation can be easily integrated into the business objects by overriding standard validation methods.</LI>
<LI>Validation failures can be tracked down to the individual objects and their properties, allowing creation of user-friendly, internationalized validation messages.</LI>
<LI>Relying on database validation for things like mandatory properties, etc., would result in errors that are meaningless or extremely hard to decode in the application context.</LI>
<LI>Application validation partially addresses shortcomings of databases that do not support real transactions (e.g. MySQL). Validation would trap the whole class of errors that would otherwise result in failure halfway through the commit, leaving database in inconsistent state.</LI>
<LI>Automating of the business objects validation takes away some burden from the UI that now has fewer things to track.</LI>
</UL>
<H3><A name="DataObjectValidation-ValidationAPI"></A>Validation API</H3>
<P>Each DataObject participating in commit operation (i.e. those in state NEW, DELETED or MODIFIED , in other words &quot;non-committed&quot;) will be validated by DataContext's ObjectStore during commit processing. Depending on the non-committed object state, ObjectStore calls one of the methods described below (description of method behavior is provided for CayenneDataObject implementation):</P>
<UL>
<LI>public void <B>validateForInsert</B>(ValidationResult validationResult)<BR>
public void <B>validateForUpdate</B>(ValidationResult validationResult)<BR>
Implementation internally calls <TT>validateForSave(..)</TT>. When overriding, in most cases developers should invoke &quot;super&quot;.</LI>
<LI>public void <B>validateForDelete</B>(ValidationResult validationResult)<BR>
This method does nothing by default and exists merely for overriding.</LI>
<LI>protected void <B>validateForSave</B>(ValidationResult validationResult)<BR>
This method only exists in CayenneDataObject (and not in DataObject). It is invoked internally from <TT>validateForInsert(..)</TT> and <TT>validateForUpdate(..)</TT>, performing some generic validation based on the DataMap information. This includes checking for nulls and for values that exceed their database size limitations. When overriding this method to include custom validation, developers should call &quot;super&quot; in most cases.</LI>
</UL>
<P>Custom validation method implementation would normally append any failures to the provided ValidationResult instance. After validating all non-committed objects, DataContext (or rather its ObjectStore) will check if the ValidationResult is not empty, and throw an exception if there is at least one failure. Typical custom validation method would look like that:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java"><SPAN class="code-keyword">public</SPAN> class Painting <SPAN class="code-keyword">extends</SPAN> _Painting {
...
<SPAN class="code-keyword">protected</SPAN> void validateForSave(ValidationResult validationResult) {
<SPAN class="code-keyword">super</SPAN>.validateForSave(validationResult);
<SPAN class="code-comment">// check business rules
</SPAN> <SPAN class="code-keyword">if</SPAN>(getEstimatedPrice().doubleValue() &lt;= 0.0) {
validationResult.addFailure(
<SPAN class="code-keyword">this</SPAN>, <SPAN class="code-comment">// source object of the failure
</SPAN> Painting.ESTIMATED_PRICE_PROPERTY, <SPAN class="code-comment">// failed property name
</SPAN> <SPAN class="code-quote">&quot;Painting price must be greater than zero.&quot;</SPAN>)); <SPAN class="code-comment">// error message
</SPAN> }
}
...
}
</PRE>
</DIV></DIV>
<H3><A name="DataObjectValidation-TurningValidationOn%2FOff"></A>Turning Validation On/Off</H3>
<P>Whether DataContext performs validation at all depends on the value of its property <TT>validatingObjectsOnCommit</TT>. Calling <TT>isValidatingObjectsOnCommit()</TT> returns currently configured value. Default value (usually &quot;true&quot;) is propagated from the parent DataDomain when DataContext is created. This default value can be configured using CayenneModeler as described in <A href="configuring-object-validation.html" title="Configuring Object Validation">Configuring Object Validation</A> section.</P>