[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