Wiki source code of EOF-Using EOF-Validation

Last modified by Pascal Robert on 2011/10/04 15:07

Show last authors
1 == Overview ==
2
3 [[http:~~/~~/developer.apple.com/legacy/mac/library/#documentation/WebObjects/Enterprise_Objects/BusinessLogic/BusinessLogic.html>>url:http://developer.apple.com/legacy/mac/library/#documentation/WebObjects/Enterprise_Objects/BusinessLogic/BusinessLogic.html||shape="rect"]]
4
5 (% style="color: rgb(0,0,0);" %)**Jerry W. Walker**
6
7 WO and EOF have an incredible array of validation mechanisms. Here are some notes you might find helpful:
8
9 * User interface:
10 ** prevent/discourage user from entering inappropriate data
11 * Formatters:
12 ** formatting
13 *** Only accepts data with valid format
14 ** type coercion
15 *** bad type raises exception
16 ** simple validation
17 *** raises exception and ignores value
18 *** must be different from current value or not assigned
19 *** WOComponent's validationFailedWithException(Throwable t, Object value, String keyPath)
20 **** Called when an Enterprise Object or formatter failed validation during an assignment.
21 **** The default implementation ignores the error.
22 **** Subclassers can override to resolve the error.
23 * Model
24 ** attribute constraints
25 *** checks for:
26 **** allows null
27 **** string length
28 **** numeric precision
29 **** relationship integrity
30 *** checks these before going to DB
31 ** relationship integrity constraints
32 *** optionality
33 **** for both to-one & to-many
34 *** delete rule
35 **** if source deleted, then what
36 *** ownership, owned object is:
37 **** deleted if relationship broken
38 **** created if relationship added
39 *** delete rules (if user tries to delete relationship source):
40 **** cascade - delete all destination objects too
41 **** nullify - nullify back references
42 **** deny - prohibit delete if there are destination objects
43 **** nothing - delete and ignore destination objects
44 * EO
45 ** property-level (or key-level) validation
46 *** called when a value changes
47 *** default methods in superclass check model based constraints
48 *** can be overridden for custom validation
49 *** called BEFORE EO's properties have changed
50 *** validation methods throw exception on failure
51 **** validateValueForKey("weight") triggers: public <type> validateWeight(Object newWeight) throws NSValidation.ValidationException {
52 ** object-level validation
53 *** called when saving insert/delete/update changes
54 **** public void validateForInsert() throws NSValidation.ValidationException
55 **** public void validateForUpdate() throws NSValidation.ValidationException
56 **** public void validateForDelete() throws NSValidation.ValidationException
57 *** all above in superclass by default call:
58 **** public void validateForSave() throws NSValidation.ValidationException
59 *** super's implementation calls key-level validation
60 *** called AFTER EO's properties have changed
61 ** validation performed when:
62 *** form values are pushed into EO attributes through bindings
63 *** saving changes in the editing context
64 *** called programmatically
65
66 == Checking for validation problems before calling saveChanges ==
67
68 You might want to display validation problems/exceptions before you try to insert/update an EO by calling saveChanges. To get the exceptions, in your component, override validationFailedWithException, with something like this:
69
70 {{code}}
71
72 public void validationFailedWithException(Throwable exception, Object value, String keyPath) {
73 super.validationFailedWithException(exception, value, keyPath);
74 session().addError(exception.getMessage());
75 }
76
77 {{/code}}
78
79 And in Session:
80
81 {{code}}
82
83 private NSMutableArray<String> _errors;
84
85 public NSArray<String> errors() {
86 return _errors.immutableClone();
87 }
88
89 public void setErrors(NSArray<String> errors) {
90 this._errors = errors.mutableClone();
91 }
92
93 public void addError(String error) {
94 _errors.addObject(error);
95 }
96
97 public boolean haveErrors() {
98 return ((_errors != null) && (_errors.count() > 0))? true: false;
99 }
100
101 @Override
102 public void awake() {
103 super.awake();
104 _errors = new NSMutableArray<String>();
105 }
106
107 {{/code}}
108
109 And before calling saveChanges on the editing context:
110
111 {{code}}
112
113 if (session().haveErrors()) {
114 return null;
115 }
116 ...
117 ec.saveChanges();
118
119 {{/code}}
120
121 == Changing an EO after Validation ==
122
123 Question: I would like to make a change to an EO after it has validated but before it has saved to the graph/DB. Is this possible?
124
125 === Chuck Hill ===
126
127 You don't want to do this, you should not want to do this, and the frameworks will fight you tooth and nail if you try. validateForSave is the gatekeeper for the object store. Its job is to ensure that nothing gets saved unless it has validated it. Modifying the object graph after validateForSave() finished would violate its very reason for existence.
128
129 As I see it, you have three options:
130
131 1. Do it in the component
132 1. Do it in the EO
133 1. Do it in another object
134
135 I agree that the component might not be the place to do this and I also don't like to have my EOs call saveChanges(). You might want to think of the third option, having some sort of ShiftManager object that is responsible for overseeing the closing and opening of shifts. It can provide information to the page on what is valid and what options there are and it can handle the two phase save.
136
137 Before I did that, I would consider some other options. Here are some ideas that might spark some of your own:
138
139 * Defer reseting the cash box balance until the //start// of the next shift. The last time I was a cashier (thankfully long ago) that is how it worked. You handed in your cash tray and discrepancy notes, the boss shook his head and muttered. He then recorded all that information. For the next worker, he then restocked the cash drawer. Often that did not happen until the next morning.
140
141 * Add a method to Shift like this:
142
143 {{code}}
144
145 public void close() throws ValidationException {
146 validateForSave();
147 cashBox().resetBalance();
148 }
149
150 {{/code}}
151
152 and in your component
153
154 {{code}}
155
156 try {
157 shift().close();
158 ec().saveChanges();
159 } catch (ValidationException v) {
160 // do the right thing
161 } catch (EOGeneralAdaptorException e) {
162 // do the right thing
163 }
164
165 {{/code}}
166
167 * I had another one, but it has slipped my mind.