From: Vance K. <va...@us...> - 2007-08-21 14:27:18
|
User: vancek Date: 07/08/21 07:27:20 Modified: andromda-ejb3/src/site/fml faq.fml andromda-ejb3/src/site changes.xml andromda-ejb3 pom.xml andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades EJB3AssociationEndFacadeLogicImpl.java andromda-ejb3/src/test/expected cartridge-output.zip andromda-ejb3/src/test/uml EJB3CartridgeTestModel.xml.zip andromda-ejb3/src/main/resources/templates/ejb3 EntityEmbeddable.vsl andromda-ejb3/src/main/uml EJB3MetafacadeModel.xml.zip andromda-ejb3/src/site/axdoc howto.xml howto2.xml Log: fix ejb-67, 68, 69 - allowing foreign key column names and constraint names to be explicitly defined Revision Changes Path 1.9 +11 -1 cartridges/andromda-ejb3/src/site/fml/faq.fml Index: faq.fml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/site/fml/faq.fml,v retrieving revision 1.8 retrieving revision 1.9 diff -u -w -r1.8 -r1.9 --- faq.fml 2 Jul 2007 14:25:12 -0000 1.8 +++ faq.fml 21 Aug 2007 14:27:09 -0000 1.9 @@ -144,5 +144,15 @@ </p> </answer> </faq> + <faq id="Inheritance_strategy_differences_between_hibernate_ejb3_cartridges"> + <question>I used to use the subclass strategy with the Hibernate cartridge. Home come I get "Cannot use identity column key generation with union-subclass mapping for" when I use the TABLE_PER_CLASS strategy with the EJB3 cartridge?</question> + <answer> + <p> + The EJB3 cartridge equivalent of the subclass inheritance strategy for the Hibernate cartridge is the + JOINED inheritance strategy. Read more about it in + <a href="http://galaxy.andromda.org/forum/viewtopic.php?t=4825">forum thread</a>. + </p> + </answer> + </faq> </part> </faqs> 1.26 +9 -0 cartridges/andromda-ejb3/src/site/changes.xml Index: changes.xml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/site/changes.xml,v retrieving revision 1.25 retrieving revision 1.26 diff -u -w -r1.25 -r1.26 --- changes.xml 21 Jul 2007 13:31:51 -0000 1.25 +++ changes.xml 21 Aug 2007 14:27:12 -0000 1.26 @@ -514,6 +514,15 @@ this is now supported with EJb 3.0. An abstract parent entity can have a relationship with any other entity and this should be available to the child inheriting entities. Add test cases to support this. </action> + <action dev="vancek" due-to="hermida" type="fix"> + JIRA EJB-67, EJB-68, EJB-69 - Improved generation of JoinColumn and JoinTable annotations for all apprpriate + associations. By default, foreign key column names have the _FK suffix. You can explicitly overwrite + FK column names by defining the @andromda.persistence.column tagged value. You can also explicitly overwrite + the foreign key constraint names by enabling hibernate extensions and modeling the + @andromda.persistence.foreignkey.constraint tagged value. Refer to the relationshipts howto for further + details. You should be aware that this patch will change the way the cartridge generates your foreign keys. + Previously, it appended the _C suffix. + </action> </release> </body> </document> \ No newline at end of file 1.20 +1 -1 cartridges/andromda-ejb3/pom.xml Index: pom.xml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/pom.xml,v retrieving revision 1.19 retrieving revision 1.20 diff -u -w -r1.19 -r1.20 --- pom.xml 13 Jun 2007 16:32:11 -0000 1.19 +++ pom.xml 21 Aug 2007 14:27:13 -0000 1.20 @@ -290,7 +290,7 @@ </plugins> </reporting> <properties> - <!--maven.test.skip>false</maven.test.skip--> + <!-- maven.test.skip>true</maven.test.skip--> <model.uri>jar:file:${pom.basedir}/src/main/uml/EJB3MetafacadeModel.xml.zip!/EJB3MetafacadeModel.xml</model.uri> <test.model.uri>jar:file:${pom.basedir}/src/test/uml/EJB3CartridgeTestModel.xml.zip!/EJB3CartridgeTestModel.xml</test.model.uri> </properties> 1.19 +84 -26 cartridges/andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades/EJB3AssociationEndFacadeLogicImpl.java Index: EJB3AssociationEndFacadeLogicImpl.java =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades/EJB3AssociationEndFacadeLogicImpl.java,v retrieving revision 1.18 retrieving revision 1.19 diff -u -w -r1.18 -r1.19 --- EJB3AssociationEndFacadeLogicImpl.java 29 Apr 2007 13:45:06 -0000 1.18 +++ EJB3AssociationEndFacadeLogicImpl.java 21 Aug 2007 14:27:13 -0000 1.19 @@ -8,6 +8,7 @@ import org.andromda.cartridges.ejb3.EJB3Globals; import org.andromda.cartridges.ejb3.EJB3Profile; +import org.andromda.metafacades.uml.AssociationEndFacade; import org.andromda.metafacades.uml.ClassifierFacade; import org.andromda.metafacades.uml.Entity; import org.andromda.metafacades.uml.EntityMetafacadeUtils; @@ -887,6 +888,20 @@ return BooleanUtils.toBoolean(String.valueOf(this.getConfiguredProperty(HIBERNATE_ASSOCIATION_ENABLE_CACHE))); } + + /** + * @see org.andromda.cartridges.ejb3.metafacades.EJB3AssociationEndFacadeLogic#handleIsForeignKeyConstraintDefined() + */ + protected boolean handleIsForeignKeyConstraintDefined() + { + boolean fkConstraintDefined = false; + if (findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_FOREIGN_KEY_CONSTRAINT_NAME) != null) + { + fkConstraintDefined = true; + } + return fkConstraintDefined; + } + /** * @see org.andromda.cartridges.ejb3.metafacades.EJB3AssociationEndFacadeLogic#handleGetForeignKeyConstraintName(java.lang.String) */ @@ -904,23 +919,22 @@ if (taggedValueObject == null) { - final ClassifierFacade type = getOtherEnd().getType(); + final ClassifierFacade type = this.getOtherEnd().getType(); if (type instanceof Entity) { - Entity entity = (Entity)type; - buffer.append(entity.getTableName()); + //Entity entity = (Entity)type; + //Instead of using the entity name, use the association end name to avoid duplication of + //FK constraint names which causes failures during table creation for some DBs (MySQL) + buffer.append( + EntityMetafacadeUtils.toSqlName( + this.getOtherEnd().getName(), + this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR))); } else { // should not happen buffer.append(type.getName().toUpperCase()); } - } - else - { - // use the tagged value - buffer.append(taggedValueObject.toString()); - } buffer.append(this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR)); @@ -949,9 +963,53 @@ buffer = new StringBuffer( EntityMetafacadeUtils.ensureMaximumNameLength(constraintName, new Short(maxLength))); buffer.append(constraintSuffix); + } + else + { + // use the tagged value + buffer.append(taggedValueObject.toString()); + } + return buffer.toString(); } + + /** + * @see org.andromda.cartridges.ejb3.metafacades.EJB3AssociationEndFacadeLogic#handleGetForeignKeyName(java.lang.String) + */ + protected String handleGetForeignKeyName(String suffix) + { + if (StringUtils.isNotBlank(suffix)) + { + suffix = new String( + this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR) + + suffix + + this.getForeignKeySuffix()); + } + else + { + suffix = this.getForeignKeySuffix(); + } + + String columnName = null; + // prevent ClassCastException if the association isn't an Entity + if (this.getType() instanceof Entity) + { + final String columnNamePrefix = + this.isConfiguredProperty(UMLMetafacadeProperties.COLUMN_NAME_PREFIX) + ? ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.COLUMN_NAME_PREFIX)) : null; + columnName = + EntityMetafacadeUtils.getSqlNameFromTaggedValue( + columnNamePrefix, + this, + UMLProfile.TAGGEDVALUE_PERSISTENCE_COLUMN, + ((Entity)this.getType()).getMaxSqlNameLength(), + suffix, + this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR)); + } + return columnName; + } + /** * @see org.andromda.cartridges.ejb3.metafacades.EJB3AssociationEndFacadeLogic#handleGetDefaultCollectionInterface() */ 1.16 +712 -646 cartridges/andromda-ejb3/src/test/expected/cartridge-output.zip <<Binary file>> 1.11 +295 -300 cartridges/andromda-ejb3/src/test/uml/EJB3CartridgeTestModel.xml.zip <<Binary file>> 1.55 +55 -12 cartridges/andromda-ejb3/src/main/resources/templates/ejb3/EntityEmbeddable.vsl Index: EntityEmbeddable.vsl =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/main/resources/templates/ejb3/EntityEmbeddable.vsl,v retrieving revision 1.54 retrieving revision 1.55 diff -u -w -r1.54 -r1.55 --- EntityEmbeddable.vsl 30 Jun 2007 03:53:48 -0000 1.54 +++ EntityEmbeddable.vsl 21 Aug 2007 14:27:17 -0000 1.55 @@ -562,13 +562,13 @@ ## Otherwise add the JoinColumn annotation. ## #* *##if (!$target.type.compositePrimaryKeyPresent) - @javax.persistence.JoinColumn(name = "$stringUtils.upperCase(${target.name})"#if ($associationEnd.columnDefinition), columnDefinition = "${associationEnd.columnDefinition}"#end) + @javax.persistence.JoinColumn(name = "${target.columnName}"#if ($associationEnd.columnDefinition), columnDefinition = "${associationEnd.columnDefinition}"#end) #* *##else #* *##set ($identifiers = $target.type.getIdentifiers()) @javax.persistence.JoinColumns ({ #* *##foreach ($attribute in $identifiers) - @javax.persistence.JoinColumn(name = "$stringUtils.upperCase(${target.name})_${attribute.columnName}", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()),#end + @javax.persistence.JoinColumn(name = "$associationEnd.getForeignKeyName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()),#end #* *##end }) @@ -580,6 +580,13 @@ ## @org.hibernate.annotations.Cascade({${target.hibernateCascadeType}}) #* *##end +#* *##if ($target.foreignKeyConstraintDefined) +## +## Override the Hibernate foreign key constraint name +## Currently does not support composite PKs +## + @org.hibernate.annotations.ForeignKey(name = "$target.getForeignKeyConstraintName(${target.type.identifier.columnName})") +#* *##end #* *##end #* *##end public $target.getterSetterTypeName ${target.getterName}() @@ -621,10 +628,13 @@ #* *##set ($argExists = false) ## ## When the target entity is a mapped superclass AND Hibernate extensions is enabled -## then instead of the @OneToMany annotations, add the @CollectionOfElements instead +## then instead of the @OneToMany annotations, add the @CollectionOfElements instead. +## This is only applied when the target entity in the association is NOT and entity. +## In this situation, the target entity is a mapped superclass. ## #* *##if ($target.type.embeddableSuperclass && $hibernateExtensionEnabled) - @org.hibernate.annotations.CollectionOfElements + @org.hibernate.annotations.CollectionOfElements#if ($target.eager)(fetch = javax.persistence.FetchType.EAGER)#end + #* *##else @javax.persistence.OneToMany(#if ($target.cascadeType)cascade = {${target.cascadeType}}#set ($argExists = true)#end#if ($associationEnd.navigable)#if ($argExists) ,#end#**#mappedBy = "${associationEnd.name}"#set ($argExists = true)#end#if ($target.eager)#if ($argExists), #end#**#fetch = javax.persistence.FetchType.EAGER#end) #* *##end @@ -633,7 +643,12 @@ ## This is only set if the relationship is unidirectional. ## #* *##if (!$associationEnd.navigable && $target.navigable) - @javax.persistence.JoinTable(name = "${associationEnd.association.tableName}") + @javax.persistence.JoinTable + ( + name = "${associationEnd.association.tableName}", + joinColumns = {#set ($identifiers = $entity.getIdentifiers())#foreach ($attribute in $identifiers)@javax.persistence.JoinColumn(name = "$associationEnd.getForeignKeyName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()), #end#end#**#}, + inverseJoinColumns = {#set ($identifiers = $target.type.getIdentifiers())#foreach ($attribute in $identifiers)@javax.persistence.JoinColumn(name = "$target.getForeignKeyName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()), #end#end#**#} + ) #* *##end #* *##if ($target.map) @javax.persistence.MapKey#if ($target.hasTaggedValue("@andromda.persistence.collection.index"))(name = "${target.collectionIndexName}")#end @@ -646,6 +661,16 @@ @javax.persistence.OrderBy #* *##end #* *##elseif ($hibernateExtensionEnabled) +## +## Override the Hibernate foreign key constraint name +## Must define the name property. If the constraint on the entity itself is not defined, then dont +## render the annotation at all. +## +#* *##if ($associationEnd.owning) +#* *##if ($associationEnd.foreignKeyConstraintDefined) + @org.hibernate.annotations.ForeignKey(#if ($associationEnd.foreignKeyConstraintDefined)name = "$associationEnd.getForeignKeyConstraintName(${associationEnd.type.identifier.columnName})"#end#if ($target.foreignKeyConstraintDefined)#if ($associationEnd.foreignKeyConstraintDefined), #end#**#inverseName = "$target.getForeignKeyConstraintName(${target.type.identifier.columnName})"#end#**#) +#* *##end +#* *##end #* *##if ($target.list) ## ## Only add the IndexColumn annotation if Hibernate extensions is enabled @@ -719,13 +744,13 @@ ## Otherwise add the JoinColumn annotation. ## #* *##if (!$target.type.compositePrimaryKeyPresent) - @javax.persistence.JoinColumn(name = "$stringUtils.upperCase(${target.name})"#if ($associationEnd.columnDefinition), columnDefinition = "${associationEnd.columnDefinition}"#end) + @javax.persistence.JoinColumn(name = "${target.columnName}"#if ($associationEnd.columnDefinition), columnDefinition = "${associationEnd.columnDefinition}"#end) #* *##else #* *##set ($identifiers = $target.type.getIdentifiers()) @javax.persistence.JoinColumns ({ #* *##foreach ($attribute in $identifiers) - @javax.persistence.JoinColumn(name = "$stringUtils.upperCase(${target.name})_${attribute.columnName}", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()),#end + @javax.persistence.JoinColumn(name = "$associationEnd.getForeignKeyName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()),#end #* *##end }) @@ -738,9 +763,14 @@ ## @org.hibernate.annotations.Cascade({${target.hibernateCascadeType}}) #* *##end +#* *##if($associationEnd.owning && $target.foreignKeyConstraintDefined) +## +## Override the Hibernate foreign key constraint name +## + @org.hibernate.annotations.ForeignKey(name = "$target.getForeignKeyConstraintName(${target.type.identifier.columnName})") +#* *##end #* *##end #* *##end - public $target.getterSetterTypeName ${target.getterName}() { return this.${target.name}; @@ -778,10 +808,13 @@ #* *##set ($argExists = false) ## ## When the target entity is a mapped superclass AND Hibernate extensions is enabled -## then instead of the @ManyToMany annotations, add the @CollectionOfElements +## then instead of the @OneToMany annotations, add the @CollectionOfElements instead. +## This is only applied when the target entity in the association is NOT and entity. +## In this situation, the target entity is a mapped superclass. ## #* *##if ($target.type.embeddableSuperclass && $hibernateExtensionEnabled) - @org.hibernate.annotations.CollectionOfElements + @org.hibernate.annotations.CollectionOfElements#if ($target.eager)(fetch = javax.persistence.FetchType.EAGER)#end + #* *##else @javax.persistence.ManyToMany(#if ($target.cascadeType)cascade = {${target.cascadeType}}#set ($argExists = true)#end#if(!$associationEnd.owning)#if ($argExists), #end#**#mappedBy = "${associationEnd.name}"#set ($argExists = true)#end#if ($target.eager)#if ($argExists), #end#**#fetch = javax.persistence.FetchType.EAGER#end) #* *##end @@ -794,8 +827,8 @@ @javax.persistence.JoinTable ( name = "${associationEnd.association.tableName}", - joinColumns = {#set ($identifiers = $entity.getIdentifiers())#foreach ($attribute in $identifiers)@javax.persistence.JoinColumn(name = "$target.getForeignKeyConstraintName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()), #end#end#**#}, - inverseJoinColumns = {#set ($identifiers = $target.type.getIdentifiers())#foreach ($attribute in $identifiers)@javax.persistence.JoinColumn(name = "$associationEnd.getForeignKeyConstraintName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()), #end#end#**#} + joinColumns = {#set ($identifiers = $entity.getIdentifiers())#foreach ($attribute in $identifiers)@javax.persistence.JoinColumn(name = "$associationEnd.getForeignKeyName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()), #end#end#**#}, + inverseJoinColumns = {#set ($identifiers = $target.type.getIdentifiers())#foreach ($attribute in $identifiers)@javax.persistence.JoinColumn(name = "$target.getForeignKeyName(${attribute.columnName})", referencedColumnName = "${attribute.columnName}")#if($velocityCount != $identifiers.size()), #end#end#**#} ) #* *##end #* *##end @@ -819,6 +852,16 @@ #* *##end #* *##end #* *##if ($hibernateExtensionEnabled) +## +## Override the Hibernate foreign key constraint name +## Only generate the ForeignKey annotation if the constraint on the entity end is defined. The +## inverseName property cannot be defined without the name property. +## +#* *##if($associationEnd.owning) +#* *##if($associationEnd.foreignKeyConstraintDefined) + @org.hibernate.annotations.ForeignKey(#if ($associationEnd.foreignKeyConstraintDefined)name = "$associationEnd.getForeignKeyConstraintName(${associationEnd.type.identifier.columnName})"#end#if ($target.foreignKeyConstraintDefined)#if ($associationEnd.foreignKeyConstraintDefined), #end#**#inverseName = "$target.getForeignKeyConstraintName(${target.type.identifier.columnName})"#end#**#) +#* *##end +#* *##end #* *##if ($target.associationCacheEnabled) ## ## Only add the Cache annotation if assocation cache and Hibernate extensions are both enabled 1.58 +238 -236 cartridges/andromda-ejb3/src/main/uml/EJB3MetafacadeModel.xml.zip <<Binary file>> 1.6 +1 -0 cartridges/andromda-ejb3/src/site/axdoc/howto.xml Index: howto.xml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/site/axdoc/howto.xml,v retrieving revision 1.5 retrieving revision 1.6 diff -u -w -r1.5 -r1.6 --- howto.xml 30 Jun 2007 03:53:48 -0000 1.5 +++ howto.xml 21 Aug 2007 14:27:19 -0000 1.6 @@ -70,6 +70,7 @@ <li><a href="howto2.html#Join_Table_Many_To_Many_And_One_To_Many">Join Table for Many-To-Many and One-To-Many Relationships</a></li> <li><a href="howto2.html#Aggregation_Composition">Aggregation and Composition</a></li> <li><a href="howto2.html#Transient_Relationships">Transient Relationships</a></li> + <li><a href="howto2.html#Foreign_Key_Column_Names_And_Foreign_Key_Constraint_Names">Foreign Key Column Names and Foreign Key Constraint Names</a></li> <li><a href="howto2.html#Tips">Tips</a></li> </ul> </li> 1.5 +58 -0 cartridges/andromda-ejb3/src/site/axdoc/howto2.xml Index: howto2.xml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/site/axdoc/howto2.xml,v retrieving revision 1.4 retrieving revision 1.5 diff -u -w -r1.4 -r1.5 --- howto2.xml 30 Jun 2007 03:53:48 -0000 1.4 +++ howto2.xml 21 Aug 2007 14:27:19 -0000 1.5 @@ -347,6 +347,64 @@ <code>@javax.persistence.Transient</code> annotation to the relationship getter. </p> </subsection> + <a name="Foreign_Key_Column_Names_And_Foreign_Key_Constraint_Names"/> + <subsection name="Foreign Key Column Names and Foreign Key Constraint Names"> + <p> + By default, the foreign key column names are defined by the cartridge and foreign key constraint + names are defined by your database on creation. This way, we don't impose any complexity + on any project. However, there are always certain environments and projects which require a + strict architecture. This is where you may need the flexibility to control the foreign key + names and foreign key constraint names. + </p> + <p> + Controlling foreign key names is relatively simple as long as you know where to model the right + tagged value. In all four association types, you can use the + <code>@andromda.persistence.column</code> tagged value on an association end to explicitly + define the foreign key name. + </p> + <p> + In a <b>many-to-one</b> or <b>one-to-one</b> association, model the + <code>@andromda.persistence.column</code> tagged value on the target association ends. In a + <b>one-to-many</b> unidirection or <b>many-to-many</b> association, you can model the + <code>@andromda.persistence.column</code> tagged value on either one or both ends of the + association. + </p> + <p> + Remember that you don't have to explicitly define the foreign key column names. The cartridge + will create a suitable name for you using either the <b>JoinColumn</b> + annotation. Using the above solution, you are effectively overwriting the auto-generated + foreign key column names. + </p> + <p> + Explicitly defining foreign key constraint names are slightly more tricky. There is no + EJB 3.0 defined solution to setting the foreign key constraint names. Hibernate has provided + an extension to the EJB 3.0 annotations which solves this limitation. This is convenient if you + are using a JEE container with Hibernate as your persistence provider. If not, you need to + check with your provider and determine a corresponding annotation. Fortunately, the EJB3 + cartridge currently works well with JBoss and since JBoss uses Hibernate, we are almost home free. + </p> + <p> + The first thing you need to do to be able to explicitly define your foreign key constraint + names is to set the value of the <b>persistenceProviderExtensions</b> namespace property + to <b>hibernate</b> in your andromda.xml. You can then model the + <code>@andromda.persistence.foreignkey.constraint</code> tagged value on the appropriate + association ends to explicitly define your foreign key constraint names. + </p> + <p> + For <b>many-to-one</b> and <b>one-to-one</b> associations, you model the + <code>@andromda.persistence.foreignkey.constraint</code> tagged value on the target association + ends. For <b>one-to-many unidirectional</b> and <b>many-to-many</b> associations, you + can model the <code>@andromda.persistence.foreignkey.constraint</code> tagged value on either + end or both ends of the association depending on what you want. + </p> + <p class="highlight"> + Keep in mind that for <b>one-to-many unidirectional</b> and <b>many-to-many</b> associations, + you must model the foreign key constraint name on the source association end if you want + to define the foreign key constraint name on the target association end. If you don't, then + neither one will be considered during generation. You can however only define the foreign key + constraint name on the source end and not the target end. + </p> + </subsection> <a name="Tips"/> <subsection name="Tips" > <p> |