Last modified by Maik Musall on 2013/07/07 17:37

Hide last authors
David Avendasora 20.1 1 Some things to avoid when working with EOF. Some of these things are contraindicated in Apple documentation, others are not. But all are things that experience shows EOF does not expect, and can lead to all sorts of trouble, including mysterious exceptions, and EOF getting confused about what changes must be saved to the database.
David Avendasora 13.1 2
Maik Musall 44.1 3 1. (((
4 ===== Don't use an EO's Constructor. =====
mark_ritchie 38.1 5
Maik Musall 44.1 6 Don't set EO properties in the EO constructor - use
Pascal Robert 40.1 7
Maik Musall 44.1 8 {{code language="none"}}
9 awakeFromInsertion(...)
10 {{/code}}
Pascal Robert 40.1 11
Maik Musall 44.1 12 or
13
14 {{code language="none"}}
15 awakeFromFetch(...)
16 {{/code}}
17
18 instead.
19 From [[Apple's Documentation>>attach:WEB.JavaDoc and other documentation@EnterpriseObjects.pdf]]:
20
21 >You may wonder why it's not recommended to initialize an enterprise object's values in an object's constructor. An enterprise object's constructor represents the earliest state in the life of a particular object. The state of an enterprise object at the point of construction is not complete; the object is not fully initialized. It may not yet have been inserted into an editing context and it might not even have been assigned a global ID. You don't ever want to manipulate an enterprise object that isn't in an editing context or that doesn't have a global ID.
22 >
23 >Therefore, any logic you add in an enterprise object's constructor may fail or be invalidated while the object finishes initializing. By providing custom logic in awakeFromInsertion or awakeFromFetch, however, you are guaranteed that an enterprise object is fully initialized.
24
25 When overriding
26
27 {{code language="none"}}
28 awakeFromInsertion(...)
29 {{/code}}
30
31 there are two times that this method can be called when the EO being inserted is not actually being initialized for the first time.
32
33 1. If it's being reinserted to a EC after it was deleted from another or the same EC. Only new EOs will have a temporary GlobalID.
David Avendasora 41.1 34 1.
Pascal Robert 40.1 35
Maik Musall 44.1 36 If it's being saved to the server-side application by a Java Client WebObjects application. These EOs will have been inserted on the client-side and likely already have values set. To avoid overriding these values, you should verify that the attribute's value is null first.
37
mark_ritchie 38.1 38 {{code}}
39 @Override
40 public void awakeFromInsertion(EOEditingContext ec) {
41 super.awakeFromInsertion(ec);
42 EOGlobalID gid = ec.globalIDForObject(this);
Pascal Robert 40.1 43 if(gid.isTemporary()) {
mark_ritchie 38.1 44 // only set default values when we're inserted into an EC for the first time.
Pascal Robert 40.1 45 if(createdDate() == null) {
46 // only set value if it hasn't already been set by a Java Client applciation.
47 setCreatedDate(new NSTimestamp());
48 }
mark_ritchie 38.1 49 }
50 }
51
52 {{/code}}
Maik Musall 44.1 53 )))
54 1. (((
55 ===== Don't change the value of an attribute or behavior of a relationship in its accessor method =====
mark_ritchie 38.1 56
Maik Musall 44.1 57 EOF calls those accessor methods many times over the life of the EO. An accessor method is the last place that you want to be making **any** changes or doing any computations to determine the value. Don't:
David Avendasora 42.1 58
Maik Musall 44.1 59 * (% style="color: rgb(255,0,0);" %)**Don't**(%%) provide default values -
60 (% style="color: rgb(0,128,0);" %)**Do**(%%) use
David Avendasora 42.1 61
Maik Musall 44.1 62 {{code language="none"}}
63 awakeFromInsertion(...)
64 {{/code}} or
David Avendasora 42.1 65
Maik Musall 44.1 66 {{code language="none"}}
67 awakeFromFetch(...)
68 {{/code}}
69 * (% style="color: rgb(255,0,0);" %)**Don't**(%%) sort a to-many relationship's values -
70 (% style="color: rgb(0,128,0);" %)**Do**(%%) write a convenience method like
David Avendasora 42.1 71
Maik Musall 44.1 72 {{code language="none"}}
73 relatedObjectsSorted()
74 {{/code}}
75 * (% style="color: rgb(255,0,0);" %)**Don't**(%%) format a String or Date or Number attribute -
76 (% style="color: rgb(0,128,0);" %)**Do**(%%) formatting in helper classes or in the Component
77 * (% style="color: rgb(255,0,0);" %)**Don't**(%%) change an attribute's data type
78 * (% style="color: rgb(255,0,0);" %)**Don't**(%%) change an attribute's value when reading a different attribute. For example: Don't call
David Avendasora 42.1 79
Maik Musall 44.1 80 {{code language="none"}}
81 setFullName(...)
82 {{/code}} when you call
David Avendasora 42.1 83
Maik Musall 44.1 84 {{code language="none"}}
85 firstName()
86 {{/code}}
87 )))
88 1. (((
89 ===== Always Insert First. =====
David Avendasora 42.1 90
Maik Musall 44.1 91 Don't do anything to an EO before inserting it into an editing context. Always insert EOs into ECs immediately. See rule #1.
92 )))
93 1. (((
94 ===== Don't modify any EO properties in {{code language="none"}}validateFor...(...){{/code}} methods =====
David Avendasora 42.1 95
Maik Musall 44.1 96 Doing this in
David Avendasora 42.1 97
Maik Musall 44.1 98 {{code language="none"}}
99 validateValueForKey(...)
100 {{/code}}
101
102 is ok as Chuck Hill noted in the list.
103 )))
104 1. (((
105 ===== Always invoke {{code language="none"}}super{{/code}} when overriding EOF methods =====
106
107 If overriding
108
109 {{code language="none"}}
110 awakeFromInsertion(...)
111 {{/code}}
112
113 , remember to call the superclass implementation. Same with
114
115 {{code language="none"}}
116 awakeFromFetch(...)
117 {{/code}}
118
119 .
120 )))
121 1. (((
122 ===== Don't use EOF in model class static initializers =====
123
Pascal Robert 40.1 124 Doing so forces EOF into operational mode before the frameworks are initialized. Use lazy loading of the entity instead.
Maik Musall 44.1 125 )))
126 1. (((
127 ===== Don't use mutable classes as attributes =====
Pascal Robert 40.1 128
Maik Musall 44.1 129 Attributes of ({{code language="none"}}NSMutableArray{{/code}}, {{code language="none"}}NSMutableDictionary{{/code}} or any other class that can change internal state after creation) will confuse EOF. If you want this effect, use immutable classes and provide cover methods to replace the immutable instance with an updated instance. For example:
130
David Avendasora 20.1 131 {{code}}
David Avendasora 13.1 132 public void addAppointment(String time, String reason) {
133 super.willChange();
134 NSMutableDictionary mutableAppointments = appointments().mutableClone();
135 mutableAppointments.setObjectForKey(reason, time);
136 setAppointments(mutableAppointments.immutableClone());
137 }
138
139 {{/code}}
Maik Musall 44.1 140 )))
141 1. (((
142 ===== Always Lock your EditingContext =====
mark_ritchie 38.1 143
David Avendasora 41.1 144 Don't call any EOEditingContext methods, or any methods on an EO in an EOEditingContext without first ensuring that the EOEditingContext is locked. That includes bindings in a WOD. It's your job to make sure the EO's that you bind to in a page are locked.
Pascal Robert 40.1 145
146 {{tip title="Project Wonder"}}
Maik Musall 44.1 147 [[Project Wonder>>doc:WONDER.WebHome]] provides auto-locking, so you don't have to worry about this.
Pascal Robert 40.1 148 {{/tip}}
Maik Musall 44.1 149 )))
150 1. (((
151 ===== Don't Expose Foreign Keys as Class Attributes =====
Pascal Robert 40.1 152
Maik Musall 44.1 153 Doing this will result in buggy unexpected behavior in EOF. Same goes for compound PKs (Primary Keys) where the compound PK values are set automatically by EOF (for example in a many-to-many join entity). However exposing compound PK attributes as class attributes is OK for an entity where you are manually setting the PK values yourself. Interestingly, even though it is not recommended, exposing a Primary Key as a class attribute will not break EOF.
154 )))
155 1. (((
156 ===== Always use .immutableClone() when iterating over a to-many relationship with a for-each loop. =====
157
158 It doesn't matter if you use the relationship directly or use a local variable that was populated by
159
160 {{code language="none"}}
161 myRelatedObjects()
162 {{/code}}
163
164 or
165
166 {{code language="none"}}
167 getValueForKey("myRelatedObjects")
168 {{/code}}
169
170 you should always use an imutableClone of the array, otherwise you will likely just have a pointer to the actual relationship, which can easily change.
171 )))