跳转到内容

WebObjects/EOF/使用 EOF/EOSharedEditingContext

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

EOSharedEditingContext,更准确地说应该叫做 EOReadOnlyEditingContext(或 EOReadMostlyEditingContext),提供了一个编辑上下文,可以在整个应用程序中使用,用于将全局共享的 EO 保存在内存中。虽然可以在共享的编辑上下文中更改对象,但这样做会非常困难,而且不会造成死锁等问题。在共享编辑上下文中放置的最佳对象类型是那些很少更改的对象,例如枚举类型对象。

性能影响

[编辑 | 编辑源代码]

启用 EOSharedEditingContexts 会对应用程序的性能造成影响。如果应用程序未使用它们,则应在应用程序构造函数中调用

 EOSharedEditingContext.setDefaultSharedEditingContext(null);

这将完全禁用共享的编辑上下文,您将不再看到任何性能损失。

Art Isbell

[编辑 | 编辑源代码]

如果您还没有,请考虑阅读 Apple 的文档

从文档中可以看出,'由于共享的编辑上下文监听 ObjectsChangedInStoreNotifications,因此当它得知对象被修改时,共享的编辑上下文就会更新'。这是否也意味着如果其他应用程序更改了数据库记录,共享的编辑上下文也会收到通知。

不。

如果不是,那么应用程序如何检测到外部数据存储中发生了一些更改?

只有当在同一进程中进行更改时,共享的编辑上下文以及该进程中的所有其他编辑上下文才会收到通知。这与所有编辑上下文的行为没有什么不同。

SharedEditingContext 是否只与由“共享所有对象”或“共享与之关联的对象”选项在“共享对象检查器”中指向的 FetchSpecifications 协同工作?或者它可以与任何常规 FetchSpecifications 协同工作?

共享的编辑上下文可以使用任何 FetchSpecification 进行编程,但 eomodel 中指定为“共享所有对象”或“共享与之关联的对象”的那些实体将被自动获取到默认的共享编辑上下文。

在应用程序级别将共享的 EO 对象加载到 sharedEditingContext 后,如何在每个页面检索已经存在于 sharedEditingContext 中的数据?

EOSharedEditingContext JavaDoc 指出

"可以使用 objectsWithFetchSpecification 和 bindObjectsWithFetchSpecification 将对象获取到共享上下文中。后一种方法使用 objectsByEntityNameAndFetchSpecificationName 更容易访问结果集。"

objectsByEntityName() 也可以使用。或者可以将它们存储在应用程序实例变量中,并通过公共应用程序方法访问。如果这样做,则资源将在会话之间共享,因此访问器方法应该同步以使访问线程安全。

'new EOEditingContext().sharedEditingContext()' 与 'EOSharedEditingContext.defaultSharedEditingContext()' 相同吗?如果不是,如何获得与应用程序级别相同的 EOSharedEditingContext 对象,该对象将用于在每个会话或每个页面获取对象?

所有编辑上下文的共享编辑上下文是默认的共享编辑上下文。editingContext.sharedEditingContext() 和 EOSharedEditingContext.defaultSharedEditingContext() 将返回相同的共享编辑上下文,除非您已明确将编辑上下文的共享编辑上下文设置为另一个共享编辑上下文。

有没有人发现使用 EOSharedEditingContext 存在任何内存问题?

如果将应用程序不需要的对象获取到共享的编辑上下文,则它可能会使用更多内存。但是,如果谨慎地仅获取应用程序可能使用的对象,则瞬时内存使用量可能少于未使用共享编辑上下文的情况,因为不会将相同的对象获取到多个编辑上下文中。由于共享的对象始终存在,因此在进程生命周期内,平均内存使用量可能会与使用共享编辑上下文的情况类似。因此,我不认为内存使用量是共享对象的一个优势或劣势,但我从未进行过比较。

共享编辑上下文的优势在于减少了数据库访问,并且无需在其他编辑上下文中创建共享对象的本地实例。

只有那些永远不会在与未共享的目标对象的关系中成为源对象的那些对象才可以共享。共享的对象也应该是只读的,因为更新它们需要一个特殊的步骤。

Jonathan Rochkind

[编辑 | 编辑源代码]

[我个人一直害怕使用 EOSharedEditingContexts,因为它们似乎有很大的出错可能性。它们的工作原理很复杂,文档并不完善,我怀疑会出现 Apple 的 bug。

Robert A Decker

[编辑 | 编辑源代码]

但是,一位用户很乐意提供他使用 EOSharedEditingContexts 的指南,并说这些指南不会导致任何问题。我在这里列出了他的指南。

我还没有遇到过 EOSharedEditingContext 和很少更改的对象的问题,只要我遵循一些规则

  • 切勿自己使用共享的编辑上下文进行获取。通过共享的编辑上下文的 objectsByEntityNameAndFetchSpecificationName 或 objectsByEntityName 方法访问所有共享对象,这些方法返回包含共享的编辑上下文持有的共享对象的字典。请重复,切勿使用共享的编辑上下文进行获取。
  • 更改对象或删除对象时,必须在没有共享 EC 的编辑上下文中进行。我总是创建一个新的 ec 并将其 sharedEc 设置为 null,然后使用以下方法将要编辑的对象复制到其中

EOUtilities.localInstanceOfObject

  • 添加对象时,必须告诉 sharedEc 刷新其刚刚添加的对象类型的数组。使用 bindObjectsWithFetchSpecificationName。

再次说明,不要使用共享的 ec 进行获取。使用这个简单的规则,我还没有遇到过应用程序运行期间很少更改的对象的任何问题。我已经使用这些规则在单独的线程中删除和更新了数千个对象,没有遇到任何问题。

Robert A Decker

[编辑 | 编辑源代码]

关于对象如何首先进入共享 ec,rob 这样写道

对于我的每个共享实体,我添加一个名为 'FetchAll' 的 FetchSpec,并在 EOModeler 检查器中将其设置为保存共享实例的 Fetch。(单击实体,查看检查器中的第三个按钮,单击 '共享与之关联的对象' 单选按钮,以选择 FetchAll FetchSpecification)。


您可以保留这些共享实体上的其他 FetchSpecs,但您不应该像通常那样使用它们 - 相反,只应将其用于对从共享实体获取的 NSArrays 进行内存中的获取和排序。

然后,在应用程序中,我有两个方法

 public static void refreshSharedEntity(String entityName) throws MarvinGeneralException {
    Application.refreshSharedEntityForFetchSpecificationName(entityName,   "FetchAll");    
 }
 
 public static void refreshSharedEntityForFetchSpecificationName(String entityName, String fetchSpecName) throws MarvinGeneralException {
   EOModelGroup modelGroup = EOModelGroup.defaultGroup();
   EOSharedEditingContext sharedEC =
   EOSharedEditingContext.defaultSharedEditingContext();
   EOFetchSpecification fs = modelGroup.fetchSpecificationNamed(fetchSpecName, entityName);
       
   if (fs == null) {            
     throw new MarvinGeneralException(Application.class.getName() + ".refreshSharedEntityForFetchSpecificationName", entityName + "." + fetchSpecName + " doesn't exist");        
   } else {
     sharedEC.bindObjectsWithFetchSpecification(fs, fetchSpecName);        
   }
 }

我使用这两个方法来更新特定实体的共享编辑上下文。

例如,对于一个实体,我有以下两个方法

 public static NSArray enclosureMasters() {
   NSDictionary objectsByEntityName = (NSDictionary)EOSharedEditingContext.defaultSharedEditingContext().objectsByEntityNameAndFetchSpecificationName();
   NSDictionary objectsForEnclosureMaster = (NSDictionary) objectsByEntityName.objectForKey("EnclosureMaster");
   NSArray enclosureMasters = (NSArray) objectsForEnclosureMaster.objectForKey("FetchAll");
   return enclosureMasters;
 }
 
 public static NSArray enclosureMasters(String fetchSpecName, NSDictionary bindings) {
   // filter in memory against all enclosure masters 
   // EOQualifier.filteredArrayWithQualifier( NSArray objects, EOQualifier aQualifier)
 
   if (bindings == null) bindings = new NSDictionary();
   EOFetchSpecification fetchSpec = EOFetchSpecification.fetchSpecificationNamed(fetchSpecName, "EnclosureMaster");
   EOQualifier boundQualifier = fetchSpec.qualifier().qualifierWithBindings(bindings, fetchSpec.requiresAllQualifierBindingVariables());
   if (boundQualifier == null) return
   EnclosureMaster.enclosureMasters(); // return all - 
              // otherwise the next call will give us an empty array
   NSArray results = EOQualifier.filteredArrayWithQualifier(EnclosureMaster.enclosureMasters(), boundQualifier);
   // we should now use the fetchSpec's sort orderings to sort the results
   NSArray sortedResults = results;
   NSArray sortOrderings = fetchSpec.sortOrderings();
   if (sortOrderings != null)
     sortedResults = EOSortOrdering.sortedArrayUsingKeyOrderArray(results, sortOrderings);
   return sortedResults;
 }

这两个方法使我可以获取所有特定类型对象的,更棒的是,可以让我对这些对象使用其他 FetchSpecs。

我将放在 EnclosureMaster 上的所有其他静态方法都将通过这两个方法进行。这样,我永远不会自己进行获取,而是只使用已经存在于内存中且由 eosharededitingcontext 持有的对象。

此外,当应用程序启动时,它将使用您之前设置的 FetchAll FetchSpec 自动获取共享对象。

添加新对象时,必须通过调用以下方法来重新加载,例如,

 Application.refreshSharedEntity("EnclosureMaster";);

编辑或删除共享实体时,SharedEditing 上下文将负责更新它持有的对象。

华夏公益教科书