跳轉到內容

WebObjects/EOF/使用 EOF/EOGenerator

來自華夏公益教科書,開放的書籍,開放的世界

如果您曾經使用過 EOModeler 的 Java 原始碼生成器,您就會知道,當您對模型物件進行更改並必須在以後合併更改時,這會多麼令人頭疼。解決此問題的一種方法是使用 EOGenerator,這是由 Rubicode Software 開發的應用程式,它使用 Generation Gap 模式從您的 EOModels 建立您的 Java 檔案。EOGenerator 為每個實體生成兩個 Java 檔案,而不是一個。以 Person 實體為例。第一個 Java 檔案是 _Person.java,其中包含所有自動生成的程式碼。第二個 Java 檔案是 Person.java,Person 擴充套件了 _Person。第二個檔案是您放置所有自定義程式碼的地方。每當您的模型更改時,只有您的 _Xxx.java 檔案會被更新,而您的自定義程式碼不會被更改。此外,EOGenerator 允許為您的檔案建立廣泛的自定義模板,這提供了將便利方法放置在您的 _Xxx.java 檔案中的能力。

與 EOModeler 的預設 Java 檔案生成以及與 FileMerge 的合併相比,使用 EOGenerator 具有若干優勢。

  • EOGenerator 使用 Generation Gap 模式,該模式提供了自動生成程式碼與自定義程式碼之間的更清晰的分隔,而無需處理任何合併。FileMerge 存在一些邊界情況,會導致您處理令人討厭的衝突。
  • EOGenerator 使用 MiscMerge 語言作為其模板。這使您能夠使用廣泛的自定義擴充套件核心模板(請參閱下面的 EOGenerator 模組部分),從而更好地支援您自己的自定義開發過程和工作流程。
  • 正如 David LaBer 所說,“所有酷炫的人都使用它——而且我們都知道,看起來很酷是*最*重要的標準”。

如何使用它

[編輯 | 編輯原始碼]

Kieran Kelleher 在他的部落格上寫了一篇關於 EOGenerator 簡介 的文章。

實際上,使用它非常簡單。快速入門是

  • 從 Rubicode 網站下載並解壓縮 EOGenerator
  • 執行以下命令
 eogenerator -model /path/to/model/YourModel.eomodeld -destination /path/to/source/folder -subclassDestination /path/to/source/folder -templatedir /path/to/EOGenerator/templates -java -packagedirs

瞧。EOGenerator 將為您生成您的 Java 檔案。讓我們分解您可以傳遞的命令

  • -define-EOGenericRecord <class>,允許您指定 _Person 類 的超類。例如,如果您使用 Project Wonder,您將指定 -define-EOGenericRecord er.extensions.ERXGenericRecord
  • -destination <path>,將生成 _Person.java 風格的 java 檔案的資料夾(不可編輯檔案)
  • -java,生成 java 檔案
  • -javaTemplate <filename>,模板目錄 (_Person) 內要使用的 Java 模板的名稱
  • -model <path>,傳入要為其生成 Java 檔案的 .eomodeld 的路徑。您實際上可以在命令列上包含多個 -model 命令
  • -packagedirs,為在 Java 檔案中定義的任何包語句生成包目錄(如果您沒有在實體上指定包名稱,則不需要。順便說一句,您應該在實體上指定包 :) )
  • -refmodel <path>,傳入生成 Java 檔案所需的 .eomodeld 的路徑,但不會為其實際生成 Java 檔案。例如,您應該為任何原型或任何您依賴的其他框架中的模型 -refmodel
  • -subclassDestination <path>,將生成 Person.java 風格的 java 檔案的資料夾(可編輯檔案)
  • -subclassJavaTemplate <filename>,模板目錄 (Person) 內要使用的 Java 子類模板的名稱
  • -templatedir <path>,包含 EOGenerator 模板的資料夾的路徑
  • -verbose,開啟詳細輸出

自定義 EOGenerator 模組

[編輯 | 編輯原始碼]

Zak Burke

[編輯 | 編輯原始碼]

允許在一對一關係上設定空值(並將其轉換為刪除)。注意,這也被包含在 Jonathan Rentzsch 的模板中。

 public void save<$ToOneRelationship.name.initialCapitalString$>(<$ToOneRelationship.destinationEntity.referenceJavaClassName$> value)
 {
   if (value == null)
   {
     <$ToOneRelationship.destinationEntity.referenceJavaClassName$> object = <$ToOneRelationship.name$>();
     if (object != null)
       removeObjectFromBothSidesOfRelationshipWithKey(object, "<$ToOneRelationship.name$>");
   }
   else
   {
     addObjectToBothSidesOfRelationshipWithKey(value, "<$ToOneRelationship.name$>");
   }
 }

Chuck Hill

[編輯 | 編輯原始碼]

返回當前 EO 與 EO 的最後一個提交版本之間的更改列表

 public NSDictionary changedProperties() {
   NSDictionary commitedValues = editingContext().committedSnapshotForObject(this);
   return changesFromSnapshot(commitedValues);
 }

Jonathan Rentzsch

[編輯 | 編輯原始碼]

Jonathan Rentzsch 提供了他的基本 EOGenerator 模板,這些模板是必不可少的

http://rentzsch.com/share/eogenerator52templates.zip

Markus Ruggiero

[編輯 | 編輯原始碼]

所有屬性和關係的常量。這允許在 addObjecttoBothSidesOfRelationshipWithKey(myObject, Person.TO_MANY_Children) 這樣的情況下進行編譯時錯誤檢查

 <$foreach attribute classAttributes.@reversedArray do$>
   public static final String ATTRIBUTE_<$attribute.name$> = "<$attribute.name$>";<$endforeach do$>
 <$foreach ToOneRelationship classToOneRelationships.@reversedArray do$>
   public static final String TO_ONE_<$ToOneRelationship.name$> = "<$ToOneRelationship.name$>";<$endforeach do$>
 <$foreach ToManyRelationship classToManyRelationships.@reversedArray do$>
   public static final String TO_MANY_<$ToManyRelationship.name$> = "<$ToManyRelationship.name$>";<$endforeach do$>

我們還大量使用實體和屬性級別的使用者資訊字典。允許生成自定義方法等等。一個例子是儲存在資料庫中的布林值,其值為“true”和“false”。

 <$if attribute.userInfo.usage == booleanFlag $>    // boolean accessors
   public void <$attribute.userInfo.setterName$>(boolean newBoolean) {
     set<$attribute.name.initialCapitalString$>(newBoolean ? "true" : "false");
   }
  
   public boolean <$attribute.userInfo.getterName$>() {
     return "true".equals(<$attribute.name$>()) ? true : false;
   }
      
   // validation
   public String validate<$attribute.name.initialCapitalString$>(String newValue) {
     if ( newValue == null ) {
       return "false";
     } else if ( !newValue.equals("true") && !newValue.equals("false") ) {
       String errorMessage = MessageHandler.format("INVALID_BOOLEAN_FLAG <$classNameWithoutPackage$>.<$attribute.name$>", null);
       throw new NSValidation.ValidationException(errorMessage);
     }
     return newValue;
   }
 <$endif$>

Mike Schrag

[編輯 | 編輯原始碼]

新增一個表示實體名稱的常量,以便您可以在獲取中引用 Person.ENTITY_NAME 而不是字串(允許在 Eclipse 中進行重構支援)

 public static final String ENTITY_NAME = "<$name$>";

在您的 EO (Person createPerson(...) ) 中新增一個靜態工廠方法,該方法向您顯示為您的實體配置了哪些必需屬性和關係(嘗試提供一個替換的“建構函式”,因為 EO 建構函式是空的)

 public static <$classNameWithoutPackage$> create<$classNameWithoutPackage$>(EOEditingContext _editingContext<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>, <$Attribute.javaValueClassName$> _<$Attribute.name$><$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>, <$ToOneRelationship.destinationEntity.referenceJavaClassName$> _<$ToOneRelationship.name$><$endif$><$endforeach do$>) {
   <$classNameWithoutPackage$> eoObject = (<$classNameWithoutPackage$>)EOUtilities.createAndInsertInstance(_editingContext, <$GEN_PREFIX$><$classNameWithoutPackage$>.ENTITY_NAME);<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>
   eoObject.set<$Attribute.name.initialCapitalString$>(_<$Attribute.name$>);<$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>
   eoObject.set<$ToOneRelationship.name.initialCapitalString$>Relationship(_<$ToOneRelationship.name$>);<$endif$><$endforeach do$>
   return eoObject;
 }

這是一個稍微花哨一點(即更難看)的版本,它還處理超類必需屬性和欄位(一級)。它跳過任何在您的子類的限制限定符中引用的屬性(因為您可能會在 awakeFromInsertion 中設定它)

 public static <$classNameWithoutPackage$> create<$classNameWithoutPackage$>(EOEditingContext editingContext<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>, <$Attribute.javaValueClassName$> <$Attribute.name$><$endif$><$endforeach do$><$foreach Attribute parentEntity.classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$><$set RestrictingQualifierKey = false$><$foreach QualifierKey restrictingQualifier.allQualifierKeys do$><$if Attribute.name = QualifierKey$><$set RestrictingQualifierKey = true$><$endif$><$endforeach do$><$if RestrictingQualifierKey = false$>, <$Attribute.javaValueClassName$> <$Attribute.name$><$endif$><$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>, <$ToOneRelationship.destinationEntity.referenceJavaClassName$> <$ToOneRelationship.name$><$endif$><$endforeach do$><$foreach ToOneRelationship parentEntity.classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>, <$ToOneRelationship.destinationEntity.referenceJavaClassName$> <$ToOneRelationship.name$><$endif$><$endforeach do$>) {
   <$classNameWithoutPackage$> eoObject = (<$classNameWithoutPackage$>)EOUtilities.createAndInsertInstance(editingContext, <$GEN_PREFIX$><$classNameWithoutPackage$>.ENTITY_NAME);<$foreach Attribute classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$>
   eoObject.set<$Attribute.name.initialCapitalString$>(<$Attribute.name$>);<$endif$><$endforeach do$><$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>
   eoObject.set<$ToOneRelationship.name.initialCapitalString$>Relationship(<$ToOneRelationship.name$>);<$endif$><$endforeach do$><$foreach Attribute parentEntity.classAttributes.@sortedNameArray do$><$if !Attribute.allowsNull$><$set RestrictingQualifierKey = false$><$foreach QualifierKey restrictingQualifier.allQualifierKeys do$><$if Attribute.name = QualifierKey$><$set RestrictingQualifierKey = true$><$endif$><$endforeach do$><$if RestrictingQualifierKey = false$>
   eoObject.set<$Attribute.name.initialCapitalString$>(<$Attribute.name$>);<$endif$><$endif$><$endforeach do$><$foreach ToOneRelationship parentEntity.classToOneRelationships.@sortedNameArray do$><$if ToOneRelationship.isMandatory$>
   eoObject.set<$ToOneRelationship.name.initialCapitalString$>Relationship(<$ToOneRelationship.name$>);<$endif$><$endforeach do$>
   return eoObject;
 }

新增一堆便利獲取方法(fetchAllPersons、fetchRequiredPerson 和其他變體)。它對複數化不智慧,因此它只是在實體名稱的末尾加上一個“s”

 public static NSArray fetchAll<$classNameWithoutPackage$>s(EOEditingContext _editingContext) {
   return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetchAll<$classNameWithoutPackage$>s(_editingContext, null);
 }
 public static NSArray fetchAll<$classNameWithoutPackage$>s(EOEditingContext _editingContext, NSArray _sortOrderings) {
   return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>s(_editingContext, null, _sortOrderings);
 }
 public static NSArray fetch<$classNameWithoutPackage$>s(EOEditingContext _editingContext, EOQualifier _qualifier, NSArray _sortOrderings) {
   EOFetchSpecification fetchSpec = new EOFetchSpecification(<$GEN_PREFIX$><$classNameWithoutPackage$>.ENTITY_NAME, _qualifier, _sortOrderings);
   fetchSpec.setIsDeep(true);
   NSArray eoObjects = _editingContext.objectsWithFetchSpecification(fetchSpec);
   return eoObjects;
 }
 public static <$classNameWithoutPackage$> fetch<$classNameWithoutPackage$>(EOEditingContext _editingContext, String _keyName, Object _value) {
   return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>(_editingContext, new EOKeyValueQualifier(_keyName, EOQualifier.QualifierOperatorEqual, _value));
 }
 public static <$classNameWithoutPackage$> fetch<$classNameWithoutPackage$>(EOEditingContext _editingContext, EOQualifier _qualifier) {
   NSArray eoObjects = <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>s(_editingContext, _qualifier, null);
   <$classNameWithoutPackage$> eoObject;
   int count = eoObjects.count();
   if (count == 0) {
     eoObject = null;
   }
   else if (count == 1) {
     eoObject = (<$classNameWithoutPackage$>)eoObjects.objectAtIndex(0);
   }
   else {
     throw new IllegalStateException("There was more than one <$classNameWithoutPackage$> that matched the qualifier '" + _qualifier + "'.");
   }
   return eoObject;
 }
       
 public static <$classNameWithoutPackage$> fetchRequired<$classNameWithoutPackage$>(EOEditingContext _editingContext, String _keyName, Object _value) {
   return <$GEN_PREFIX$><$classNameWithoutPackage$>.fetchRequired<$classNameWithoutPackage$>(_editingContext, new EOKeyValueQualifier(_keyName, EOQualifier.QualifierOperatorEqual, _value));
 }
 public static <$classNameWithoutPackage$> fetchRequired<$classNameWithoutPackage$>(EOEditingContext _editingContext, EOQualifier _qualifier) {
   <$classNameWithoutPackage$> eoObject = <$GEN_PREFIX$><$classNameWithoutPackage$>.fetch<$classNameWithoutPackage$>(_editingContext, _qualifier);
   if (eoObject == null) {
     throw new NoSuchElementException("There was no <$classNameWithoutPackage$> that matched the qualifier '" + _qualifier + "'.");
   }
   return eoObject;
 }

新增用於獲取 EO 的本地例項的方法。如果您對可能為空的 EO 有引用,靜態方法會很方便(它首先執行空值檢查)

 public <$classNameWithoutPackage$> localInstanceOf<$classNameWithoutPackage$>(EOEditingContext _editingContext) {
   return (<$classNameWithoutPackage$>)EOUtilities.localInstanceOfObject(_editingContext, this);
 }
 public static <$classNameWithoutPackage$> localInstanceOf<$classNameWithoutPackage$>(EOEditingContext _editingContext, <$classNameWithoutPackage$> _eo) {
   return (_eo == null) ? null : (<$classNameWithoutPackage$>)EOUtilities.localInstanceOfObject(_editingContext, _eo);
 }

如果您曾經想在您的 EO 上限定一個 toMany 關係,但有時您想使用獲取規範獲取它們,有時您想在記憶體中進行過濾,您可以使用以下方法

 <$if !ToManyRelationship.inverseRelationship$>
 	public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier) {
 		return <$ToManyRelationship.name$>(qualifier, null);
 	}
 <$endif$>
 <$if ToManyRelationship.inverseRelationship$>
 	public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier) {
 		return <$ToManyRelationship.name$>(qualifier, null, false);
 	}
 
 	public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier, boolean fetch) { 
 		return <$ToManyRelationship.name$>(qualifier, null, fetch);
 	}
 <$endif$>
 
 	public NSArray <$ToManyRelationship.name$>(EOQualifier qualifier, NSArray sortOrderings<$if ToManyRelationship.inverseRelationship$>, boolean fetch<$endif$>) {
 		NSArray results;
 <$if ToManyRelationship.inverseRelationship$>
 		if (fetch) {
 			EOQualifier fullQualifier;
 			EOQualifier inverseQualifier = new EOKeyValueQualifier(<$ToManyRelationship.destination.className$>.<$ToManyRelationship.inverseRelationship.name.uppercaseUnderbarString$>_KEY, EOQualifier.QualifierOperatorEqual, this);
 			if (qualifier == null) {
 				fullQualifier = inverseQualifier;
 			}
 			else {
 				NSMutableArray qualifiers = new NSMutableArray();
 				qualifiers.addObject(qualifier);
 				qualifiers.addObject(inverseQualifier);
 				fullQualifier = new EOAndQualifier(qualifiers);
 			}
 			results = <$ToManyRelationship.destination.className$>.fetch<$ToManyRelationship.destination.name$>s(editingContext(), fullQualifier, sortOrderings);
 		}
 		else {
 <$endif$>
 			results = <$ToManyRelationship.name$>();
 			if (qualifier != null) {
 				results = EOQualifier.filteredArrayWithQualifier(results, qualifier);
 			}
 			if (sortOrderings != null) {
 				results = EOSortOrdering.sortedArrayUsingKeyOrderArray(results, sortOrderings);
 			}
 <$if ToManyRelationship.inverseRelationship$>
 		}
 <$endif$>
 		return results;
 	}

John Huss

[編輯 | 編輯原始碼]

我想分享今天學到的一點很棒的知識。如果您使用的是 Java 1.5,您可以在 _EO 基礎類的模板中新增 @SuppressWarnings("all"),並消除惱人的編譯器訊息(通常是不必要的匯入語句)。

 @SuppressWarnings("all")
 public class _Invoice extends ERXGenericRecord {
 }

Guido Neitzer

[編輯 | 編輯原始碼]

在您的 EOGenerator 模板中建立 awakeFromInsertion() 和 awakeFromFetch() 作為方法存根,該方法存根僅呼叫 super() 並有一個“在此處初始化您的物件...”的註釋。您只需要在那個地方放入程式碼,並且不可能忘記呼叫 super()。以下是一個示例

   /** 
    * Initialization of the instance while inserting it into an editing context
    */
    public void awakeFromInsertion (EOEditingContext editingContext) {
        super.awakeFromInsertion (editingContext);
        // initialize your object here
    }

這是來自我的 JavaSubclassSourceTemplate.eotemplate 的

華夏公益教科書