跳轉到內容

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 Mods 部分),更好地支援您自己的自定義開發流程和工作流程。
  • 正如 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>,要在模板目錄內使用的 Java 模板的名稱(_Person)
  • -model <path>,傳遞您想要為其生成 Java 檔案的 .eomodeld 的路徑。您實際上可以在命令列中包含多個 -model 命令
  • -packagedirs,為 Java 檔案中定義的任何包語句生成包目錄(如果您不在實體上指定包名稱則不需要。順便說一句,您應該在實體上指定包  :) )
  • -refmodel <path>,傳遞 .eomodeld 的路徑,該路徑是生成 Java 檔案所必需的,但實際上不會為其生成 Java 檔案。例如,您應該 -refmodel 任何原型,或者您所依賴的其他框架中的任何模型
  • -subclassDestination <path>,Person.java 樣式的 Java 檔案將被生成到的資料夾(可編輯的檔案)
  • -subclassJavaTemplate <filename>,要在模板目錄內使用的 Java 子類模板的名稱(Person)
  • -templatedir <path>,包含 EOGenerator 模板的資料夾的路徑
  • -verbose,開啟詳細輸出

自定義 EOGenerator 修改

[編輯 | 編輯原始碼]

Zak Burke

[編輯 | 編輯原始碼]

允許在一對一關係上設定 null(並將其變成刪除)。請注意,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$>

我們也大量使用實體和屬性級別的使用者資訊字典。允許生成自定義方法等等。一個例子是作為字串儲存在 DB 中的布林值,其值是“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 本地例項的方法。如果您有一個可能為 null 的 EO 的引用,則靜態方法很有用(它首先執行 null 檢查)

 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

華夏公益教科書