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,開啟詳細輸出
允許在一對一關係上設定 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$>");
}
}
返回當前 EO 與 EO 的最後提交版本之間的更改列表
public NSDictionary changedProperties() {
NSDictionary commitedValues = editingContext().committedSnapshotForObject(this);
return changesFromSnapshot(commitedValues);
}
Jonathan Rentzsch 提供了他的基本 EOGenerator 模板,這些模板是必不可少的
http://rentzsch.com/share/eogenerator52templates.zip
所有屬性和關係的常量。這允許在諸如 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$>
新增一個代表實體名稱的常量,以便您可以在提取中引用 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;
}
我想分享今天學到的一點很棒的知識。如果您使用的是 Java 1.5,您可以在 _EO 基類的模板中新增 @SuppressWarnings("all"),並消除煩人的編譯器訊息(通常是不必要的匯入語句)。
@SuppressWarnings("all")
public class _Invoice extends ERXGenericRecord {
}
在您的 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