[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