[hibernate-dev] Preventing duplicate ForeignKey generation

Vlad Mihalcea mihalcea.vlad at gmail.com
Mon Jan 9 07:02:44 EST 2017


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>
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)
>
> 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
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>


More information about the hibernate-dev mailing list