跳转到内容

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

华夏公益教科书