Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Accessing Primary Keys

When your primary key is not visible as a class property, the documented way to obtain the primary key values is with EOUtilities.primaryKeyForObject(). This works, but in the case where you have a single non-compound primary key, you need a few more lines of code to pull out this pk value. More troubling, the EOUtilities method, when called with a fault, will cause the fault to be resolved. The fault does not really need to be resolved to get the primary key, as the pk value is present even in the fault.

...

Code Block
public static Integer singleIntegerPrimaryKeyForObject(EOEnterpriseObject eo) {
    EOEditingContext ec = eo.editingContext();
    if (ec == null) {
        //you don't have an EC! Bad EO. We can do nothing. 
        return null;
    }
    EOGlobalID gid = ec.globalIDForObject(eo);
    if (gid.isTemporary()) {
        //no pk yet assigned
        return null;
    }
    EOKeyGlobalID kGid = (EOKeyGlobalID) gid;
    NSArray keyValues = kGid.keyValuesArray();
    if (keyValues.count() != 1 ||
        ! (keyValues.objectAtIndex(0) instanceof Integer))
        return null;
 
    return (Integer) keyValues.objectAtIndex(0);
       
}

You can also use the EOUtilities method but please note that, at least as of WO5, there are two somewhat undesirable aspects of this EOUtilities code:

  • If the EO is a fault, calling the EOUtilities method will cause the fault to be resolved, possibly requiring a trip to the db, even though pk info is already present in the fault and the trip to the db is really unneccesary at this point.
  • If the EO has just been inserted and not yet committed, it does not have a pk yet, and the EOUtilities code will throw an exception. And it's not a logical exception corresponding to "no pk yet", but rather some uncaught exception thrown by some surprised Apple code.

Assigning Primary Keys

Wiki Markup
Usually EOF doesn't get around to generating/inserting primary keys until you actually saveChanges() on an EOEditingContext containing newly created about-to-be saved EOEnterpriseObjects.
But sometimes you want to assign a permanent pk as soon as you create the EOEnterpriseObject, not wait until it's actually committed to the db. Here's some code to do that, which, in a given situation, will generate the pk in the same way that EOF would have generated it later, but do it right away. \[WO:Thanks to Pierre Barnard\]

Code Block
public void _insertObjectWithGlobalID(EOEnterpriseObject eo, EOGlobalID globalID)
 {
   EOEntity entity = EOUtilities.entityNamed(this, eo.entityName());
   EODatabaseContext dbContext = EOUtilities.databaseContextForModelNamed(this, entity.model().name());
   NSDictionary pkDict = primaryKeyDictionaryForDatabaseContextAndEntity(dbContext, entity);
               
   if (pkDict == null || pkDict.count() != 1)
   {
     NSLog.err.appendln("Failed to generate primary key for entity " + entity.name() + ", or pk is compound.");
   } else
   {
     Object pk = pkDict.allValues().lastObject();
     globalID = EOKeyGlobalID.globalIDWithEntityName(entity.name(), new Object[] { pk });
   }
     
   super._insertObjectWithGlobalID(eo, globalID);
 }
 
 public static NSDictionary primaryKeyDictionaryForDatabaseContextAndEntity(EODatabaseContext dbContext, EOEntity entity) {
   NSDictionary pk = null;
   try {
     dbContext.lock();
     EOAdaptorChannel adaptorChannel = dbContext.availableChannel().adaptorChannel();
     if (!adaptorChannel.isOpen()) {
       adaptorChannel.openChannel();
     }
     pk = (NSDictionary) adaptorChannel.primaryKeysForNewRowsWithEntity(1, entity).lastObject();
   }
   catch (Exception e) {
     NSLog.err.appendln("Can't get primary keys for entity " + entity.name() + "  " + e);
   }
   finally {
     dbContext.unlock();
     return pk;
   }
 }

...

BTW, I believe EOF does some optimization by retrieving PKs in batches rather than one by one. You lose that when using the above code.Category:WebObjects