跳转到内容

WebObjects/EOF/使用 EOF/主键

来自维基教科书,开放的书籍,为开放的世界

访问主键

[编辑 | 编辑源代码]

当你的主键不可见为类属性时,获得主键值的文档化方法是使用 EOUtilities.primaryKeyForObject()。这可行,但如果你有一个单一的非复合主键,你需要几行代码来提取这个主键值。更麻烦的是,当 EOUtilities 方法在错误上调用时,会导致错误被解析。错误实际上并不需要解析来获得主键,因为主键值即使在错误中也存在。

以下方法适用于具有单个 Integer 主键的 EO,用于提取该主键值,并且在对错误值调用时不会解析错误(可能导致访问数据库)。

   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);
       
   }

你也可以使用 EOUtilities 方法,但请注意,至少在 WO5 中,此 EOUtilities 代码有两个不太理想的方面。

  • 如果 EO 是一个错误,调用 EOUtilities 方法会导致错误被解析,可能需要访问数据库,即使主键信息已存在于错误中,访问数据库在此时实际上是不必要的。
  • 如果 EO 刚刚被插入并且尚未提交,它还没有主键,EOUtilities 代码将抛出异常。这并不是一个与“还没有主键”相对应的逻辑异常,而是一个由一些意外的 Apple 代码抛出的未捕获异常。

分配主键

[编辑 | 编辑源代码]

通常 EOF 不会在您实际在包含新创建的即将保存的 EOEnterpriseObjects 的 EOEditingContext 上调用 saveChanges() 之前生成/插入主键。

但是,有时您希望在创建 EOEnterpriseObject 时立即分配一个永久主键,而不是等到它真正提交到数据库。以下是一些代码来实现这一点,它会在给定情况下以与 EOF 稍后生成主键相同的方式生成主键,但会立即执行。[感谢 Pierre Barnard]

 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;
   }
 }

EOEditingContext 中有 2 个 insertObjectWithGlobalID 方法。其中一个方法名以下划线开头。常规方法似乎调用了该方法。对于大多数用途,覆盖常规方法就足够了。但是,对于 JavaClient,常规方法不会被调用。在服务器端,只有带下划线的方法会被调用。您必须在服务器端上下文中覆盖带下划线的方法,因为以上代码仅在服务器端有效。

如果您在标准 WO 应用程序中使用嵌套 EC,那么如果您希望父 EC 处理主键创建,则可能需要覆盖相同的部分私有方法。

顺便说一句,我相信 EOF 通过批量检索主键而不是逐个检索主键来进行一些优化。当使用以上代码时,您会失去这种优化。

华夏公益教科书