[hibernate-dev] Preventing duplicate ForeignKey generation

Milo van der Zee milo at vanderzee.org
Wed May 10 12:07:52 EDT 2017


Finally done... See https://github.com/hibernate/hibernate-orm/pull/1906

MAG,
Milo


On 01/09/2017 01:02 PM, Vlad Mihalcea wrote:
> Thanks,
>
> Please send a Pull Request with a replicating test case.
>
> Vlad
>
> On Wed, Dec 28, 2016 at 12:05 AM, Milo van der Zee <milo at vanderzee.org 
> <mailto:milo at vanderzee.org>> wrote:
>
>     Hello all,
>
>     During development of applications I'm used to set the schema creation
>     to 'update' (hbm2ddl.auto = update). This makes life a bit easier.
>     Issue with the newer version of Hibernate is that the name of the
>     generated keys changed and so all keys are regenerated. For the large
>     databases I use this takes hours and has to be done every time a fresh
>     copy from production is taken to the development environment.
>
>     I do use meaningful names for the indexes where possible. But when
>     using
>     abstract classes used by the entities that is not possible because the
>     same fields from the abstract are used by many entity classes and so
>     would end up having the same index names.
>
>     I checked the code that decides if the index needs to be created and
>     found that it only checks the name of the index. Not what the index
>     actually does. This is why I changed that piece of code to be a bit
>     smarter. It is desinged for simple constraints from one column to
>     another column. Not for multi to multi column indexes and constraints.
>
>     I created a Jira issue for it but nobody notices it and there are no
>     comments or anything else. So now I try it here :)
>     Jira HHH-10934 (https://hibernate.atlassian.net/browse/HHH-10934
>     <https://hibernate.atlassian.net/browse/HHH-10934>)
>
>     Code fragment I put in SchemaMigratorImpl.java:
>
>     private  ForeignKeyInformation findMatchingForeignKey(ForeignKey
>     foreignKey, TableInformation tableInformation) {
>             if  (foreignKey.getName() ==null) {
>                     return  null;
>             }
>
>             /*
>              * Find existing keys based on referencing column and
>     referencedTable
>              */
>             String  referencingColumn = foreignKey.getColumn(0).getName();
>             String  referencedTableName =
>     foreignKey.getReferencedTable().getName();
>             Iterable<ForeignKeyInformation> existingForeignKeys =
>     tableInformation.getForeignKeys();
>             for  (ForeignKeyInformation existingKey :
>     existingForeignKeys) {
>                     Iterable<ColumnReferenceMapping>
>     columnReferenceMappings = existingKey.getColumnReferenceMappings();
>                     for  (ColumnReferenceMapping mapping :
>     columnReferenceMappings) {
>                             String  existingReferencingColumn =
>     mapping.getReferencingColumnMetadata().getColumnIdentifier().getText();
>                             String  existingReferencedTableName =
>     mapping.getReferencedColumnMetadata().getContainingTableInformation().getName().getTableName().getCanonicalName();
>                             if 
>     (referencingColumn.equals(existingReferencingColumn) &&
>     referencedTableName.equals(existingReferencedTableName)) {
>                                     return  existingKey;
>                             }
>                     }
>             }
>
>             // If not yet found check based on key name  return 
>     tableInformation.getForeignKey(Identifier.toIdentifier(foreignKey.getName()));
>     }
>
>     Or if you prever the Java 8 way:
>
>     private  ForeignKeyInformation findMatchingForeignKey(ForeignKey
>     foreignKey, TableInformation tableInformation) {
>             log.debug("findMatchingForeignKey");
>             if  (foreignKey.getName() ==null)return  null;
>
>             /*
>              * Find existing keys based on referencing column and
>     referencedTable
>              */
>             String  referencingColumn = foreignKey.getColumn(0).getName();
>             String  referencedTableName =
>     foreignKey.getReferencedTable().getName();
>             Predicate<ColumnReferenceMapping> mappingPredicate = m ->
>     referencingColumn.equals(m.getReferencingColumnMetadata().getColumnIdentifier().getText())
>                             &&
>     referencedTableName.equals(m.getReferencedColumnMetadata().getContainingTableInformation().getName().getTableName().getCanonicalName());
>             for  (ForeignKeyInformation existingKey :
>     tableInformation.getForeignKeys()) {
>                     boolean  found =
>     StreamSupport.stream(existingKey.getColumnReferenceMappings().spliterator(),false).anyMatch(mappingPredicate);
>                     if  (found)return  existingKey;
>             }
>
>             // If not yet found check based on key name  return 
>     tableInformation.getForeignKey(Identifier.toIdentifier(foreignKey.getName()));
>     }
>
>     The calling method does not use the returned value. It only checks if
>     the returned value is null or not. So this could also be cleaned by
>     changing the method to return a boolean and then remove the for
>     loop in
>     java-8 and use flatmap. But first let us agree on the validity of the
>     idea to change this piece of code.
>
>     I hope anybody would like to have a look at it and if there is any
>     change that the idea (not this actual very quick/dirty implementation)
>     goes into the system I'll clean it up and do some actual tests for
>     more
>     complex database structures. I did not even check the junit tests yet.
>     At the moment it is good enough for me but I think it could be
>     something
>     more people would benefit from.
>
>     Thanks,
>     Milo van der Zee
>
>
>     _______________________________________________
>     hibernate-dev mailing list
>     hibernate-dev at lists.jboss.org <mailto:hibernate-dev at lists.jboss.org>
>     https://lists.jboss.org/mailman/listinfo/hibernate-dev
>     <https://lists.jboss.org/mailman/listinfo/hibernate-dev>
>
>



More information about the hibernate-dev mailing list