WebObjects/EOF/使用 EOF/问题
本节描述使用企业对象框架时有时会遇到的一些问题和错误。
- 作者:Francis Labrie
- 受影响的产品:WebObjects 5.2.x, 5.3.x
- 错误参考:rdar://4571773
有时,在WebObjects应用程序中使用多个使用共享对象的数据库模型时,模型加载、初始化和连接会简单地失败,并出现奇怪且意外的异常。常见的异常是
java.lang.IllegalStateException: registeredDatabaseContextForModel() 无法为模型注册数据库上下文
<模型名称>
at com.webobjects.eoaccess.EODatabaseContext.registeredDatabaseContextForModel(EODatabaseContext.java:1145)
- ...
java.lang.IllegalStateException: addOrderByAttributeOrdering: 尝试为 com.webobjects.eocontrol.EOSortOrdering <class com.webobjects.eocontrol.EOSortOrdering(
<属性名称>compareAscending)> 生成 SQL 失败,因为通过键 '
<属性名称>' 标识的属性无法从实体 '
<实体名称>' 访问。
at com.webobjects.eoaccess.EOSQLExpression.addOrderByAttributeOrdering(EOSQLExpression.java:1803)
- ...
- 等等。
我在多个邮件列表中看到了有关此错误的报告,但没有一个报告能找到正确的解决方案或合理的解释。
- http://lists.apple.com/archives/webobjects-dev/2005/Aug/msg00295.html
- http://www.wodeveloper.com/omniLists/webobjects-dev/2004/September/msg00255.html
我最终发现这个问题与模型加载和初始化顺序有关。大多数情况下,EOF 都能完美地初始化一组模型。但在某些情况下,它就会失败。
最好的解决方案是让 EOF 动态分析模型组,为每个组构建一个包含所有实体的依赖关系图,并根据此图对模型和实体的初始化进行排序。但这种解决方案稍微复杂一些,通常应该直接集成到 EOAccess 层中。
为了使用更简单的解决方案来解决此错误,可以在每个模型的userInfo
字典中添加priority
键,并将其分配给一个四位数的值,例如:0100
、0500
、2000
等。必须使用具有相同位数的优先级值,因为这些值将被转换为字符串,如果您设置的优先级为500
,则字符串值将被视为高于优先级为1000
的值。
然后,创建一个静态方法,使用按优先级排序的组中的每个模型执行assertConnectionDictionaryIsValid()
操作。
private static final NSArray _PriorityDescendingModelSortOrdering = new NSArray(new Object[] { EOSortOrdering.sortOrderingWithKey("userInfo.priority", EOSortOrdering.CompareDescending), EOSortOrdering.sortOrderingWithKey("name", EOSortOrdering.CompareAscending) }); ... public static void assertModelGroupConnectionDictionariesAreValid(EOEditingContext editingContext, EOModelGroup modelGroup) { Enumeration models; EOAdaptor adaptor; EODatabaseContext databaseContext; EOModel model; // Get models enumerator from default group models = EOSortOrdering.sortedArrayUsingKeyOrderArray(modelGroup.models(), _PriorityDescendingModelSortOrdering).objectEnumerator(); while(models.hasMoreElements()) { model = (EOModel)models.nextElement(); NSLog.debug.appendln(" Connecting " + model.name() + " model, userInfo = " + model.userInfo() + "..."); databaseContext = EODatabaseContext.registeredDatabaseContextForModel(model, editingContext); adaptor = databaseContext.adaptorContext().adaptor(); // Test connection dictionary adaptor.assertConnectionDictionaryIsValid(); NSLog.debug.appendln(" The \"" + model.name() + "\" model is connected."); } // while } // assertConnectionDictionariesAreValid
此处的排序顺序是按模型优先级降序和模型名称升序排序,以确保排序结果的一致性。
您将不得不找到正确的模型顺序:您可以通过逻辑绘制依赖关系图来推断它,也可以通过测试和错误来找到它。通常,当抛出上述异常时,这是因为模型初始化完成得太晚。我通常将框架模型的优先级设置为从1000
(低)到9000
(高),将应用程序模型的优先级设置为从0100
(低)到0900
(高)。
对于某些情况,此解决方案仍然无济于事(请参阅此邮件)。我怀疑模型中的实体排序是问题所在(请参阅下面的#EOF 在模型中未正确排序时无法获取或保存实体)。如果仍然不是这种情况,您可以尝试在Project Wonder中使用ERXSharedEOLoader 类。
- 作者:Francis Labrie
- 受影响的产品:WebObjects 5.2.x, 5.3.x
- 错误参考
有时,在WebObjects应用程序中,在数据库模型中使用实体继承时,获取或保存数据可能会简单地失败,并出现奇怪且意外的异常。常见的异常是
com.webobjects.eoaccess.EOGeneralAdaptorException: sqlStringForKeyValueQualifier: 尝试为
<限定符类>(
<限定符表达式>) 生成 SQL 失败,因为通过键 'NeededByEOF0' 标识的属性无法从实体
<实体名称>访问。
at com.webobjects.eoaccess.EODatabaseContext._exceptionWithDatabaseContextInformationAdded(EODatabaseContext.java:4685)
- ...
- 等等。
通常,这种错误发生在父实体位于另一个模型中,而该模型是在当前实体模型初始化之后初始化的(请参阅上面的#EOF 在未明确排序时无法初始化模型),或者父实体在当前模型中按字母顺序排列的实体列表中位于当前实体之后。为了说明后一种情况:如果您的抽象父实体名称为“Flower”,并且您正在获取具体子实体“Anemone”,而这两个实体都是同一个模型的一部分,那么您可能会在第一次获取“Anemone”时遇到这种异常。
为了避免此异常,只需在文本编辑器中编辑“index.eomodeld”文件并重新排序数组中的实体引用,将父实体置于子实体之上。但您随后需要小心使用EOModeler:每次修改和保存模型时,都需要重新排序这些实体引用。
- 作者:最初由 Chuck Hill 报告
- 受影响的产品:WebObjects 5.2.x, 5.3.x
- 错误参考
当子实体的父实体具有设置为传播主键的关系时,在从编辑上下文保存更改时插入任何新的子实体都会引发完整性违规异常,因为主键列设置为null
。
为了避免此错误,取消选中父实体的传播主键关系属性。不幸的是,如果父实体不是抽象的,则此解决方案将不适用:您可能需要修改关系建模本身。