EOF-Using EOF-The EOF Commandments

Version 13.1 by David Avendasora on 2011/05/31 14:29
Warning: For security reasons, the document is displayed in restricted mode as it is not the current version. There may be differences and errors due to this.

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.

  1. h5. Don't use an EO's Constructor.
    Don't set EO properties in the EO constructor - use awakeFromInsertion(...) or awakeFromFetch(...) instead.
    From Apple's Documentation:

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.




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.

When overriding awakeFromInsertion(...) there are two times that this method can be called when the EO being inserted is not actually being initialized for the first time.


    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.
    2. 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.

@Override
public void awakeFromInsertion(EOEditingContext ec) {
   super.awakeFromInsertion(ec);
   EOGlobalID gid = ec.globalIDForObject(this);
   if(gid.isTemporary()) {
       // only set default values when we're inserted into an EC for the first time.
       if(createdDate() == null) {
           // only set value if it hasn't already been set by a Java Client applciation.
           setCreatedDate(new NSTimestamp());
        }
    }
}
  1. h5. Don't change the value of an attribute or behavior of a relationship in its accessor method
    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:
    • Unknown macro: color. Click on this message for details.
      provide default values - Unknown macro: color. Click on this message for details.
      use awakeFromInsertion(...) or awakeFromFetch(...)
    • Unknown macro: color. Click on this message for details.
      sort a to-many relationship's values - Unknown macro: color. Click on this message for details.
      write a convenience method like relatedObjectsSorted()
    • Unknown macro: color. Click on this message for details.
      format a String or Date or Number attribute - Unknown macro: color. Click on this message for details.
      formatting in helper classes or in the Component
    • Unknown macro: color. Click on this message for details.
      change an attribute's data type
    • Unknown macro: color. Click on this message for details.
      change an attribute's value when reading a different attribute. For example: Don't call setFullName(...) when you call firstName()
  2. h5. Always Insert First.
    Don't do anything to an EO before inserting it into an editing context. Always insert EOs into ECs immediately. See rule #1.
  3. h5. Don't modify any EO properties in validateFor...(...) methods
    Doing this in validateValueForKey(...) is ok as Chuck Hill noted in the list.
  4. h5. Always invoke super when overriding EOF methods
    If overriding awakeFromInsertion(...), remember to call the superclass implementation. Same with awakeFromFetch(...).
  5. h5. Don't use EOF in model class static initializers
    Doing so forces EOF into operational mode before the frameworks are initialized. Use lazy loading of the entity instead.
  6. h5. Don't use mutable classes as attributes
    Attributes of (NSMutableArray, NSMutableDictionary 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:

public void addAppointment(String time, String reason) {
    super.willChange();
    NSMutableDictionary mutableAppointments = appointments().mutableClone();
    mutableAppointments.setObjectForKey(reason, time);
    setAppointments(mutableAppointments.immutableClone());
}
  1. h5. Always Lock your EditingContext
    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.
Success

Project Wonder

[Project Wonder|WONDER:] provides auto-locking, so you don't have to worry about this.