[hibernate-dev] Preventing duplicate ForeignKey generation

Vlad Mihalcea mihalcea.vlad at gmail.com
Wed May 10 13:38:54 EDT 2017


Thanks,

Vlad

On Wed, May 10, 2017 at 7:07 PM, Milo van der Zee <milo at vanderzee.org>
wrote:

> 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>
> 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().getContainingTableInfo
>> rmation().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.g
>> etReferencedColumnMetadata().getContainingTableInformation()
>> .getName().getTableName().getCanonicalName());
>>         for  (ForeignKeyInformation existingKey :
>> tableInformation.getForeignKeys()) {
>>                 boolean  found = StreamSupport.stream(existingK
>> ey.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