跳轉到內容

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 上下文將負責更新它持有的物件。

華夏公益教科書