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 通过批量检索主键而不是逐个检索主键来进行一些优化。当使用以上代码时,您会失去这种优化。