[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