-
-
Notifications
You must be signed in to change notification settings - Fork 972
Fix join-table foreign keys to use resolved entity table names (#15736) #16028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 8.0.x
Are you sure you want to change the base?
Changes from 4 commits
bfdbbe8
d1ca11f
a77c8f2
aa02d74
ba081ef
3195e1d
0ca2559
546fea4
4da31cc
d2655f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -212,10 +212,7 @@ default String resolveJoinTableForeignKeyColumnName(PersistentEntityNamingStrate | ||||||||||
| return ofNullable(getHibernateMappedForm()) | |||||||||||
| .map(PropertyConfig::getJoinTableColumnConfig) | |||||||||||
| .map(ColumnConfig::getName) | |||||||||||
| .orElseGet(() -> namingStrategy.resolveColumnName(getHibernateAssociatedEntity() | |||||||||||
| .getHibernateRootEntity() | |||||||||||
| .getJavaClass() | |||||||||||
| .getSimpleName()) + | |||||||||||
| .orElseGet(() -> resolveAssociatedEntityTableName(namingStrategy) + | |||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I compared the generated H2 schema on this branch against the merge base with these domain classes: @Entity class ProbeAuthor { String name
static hasMany = [books: ProbeBook]
static mapping = { table 'writer' } }
@Entity class ProbeBook { String title
static belongsTo = ProbeAuthor
static hasMany = [authors: ProbeAuthor]
static mapping = { table 'catalog_book' } }
@Entity class ProbeShelf { String label
static hasMany = [shelved: ProbeBook] } // unidirectional
Two consequences worth deciding on explicitly:
Could we either extend the resolution to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the detailed repro — went with your second option: kept the code narrowly scoped to what it actually fixes (the associated-entity FK column of a unidirectional |
|||||||||||
| GrailsDomainBinder.FOREIGN_KEY_SUFFIX); | |||||||||||
| } | |||||||||||
|
|
|||||||||||
|
|
@@ -227,8 +224,10 @@ default String joinTableColumName(PersistentEntityNamingStrategy namingStrategy) | ||||||||||
| if (present) { | |||||||||||
| columnName = joinColumnMappingOptional.get().getName(); | |||||||||||
| } else { | |||||||||||
| var clazz = namingStrategy.resolveColumnName(referencedType.getName()); | |||||||||||
| var prop = namingStrategy.resolveTableName(getName()); | |||||||||||
| var clazz = isBasic() ? | |||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both callers of If it is intended as future-proofing, I'd rather drop the ternary (or move
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dropped the ternary in 4da31cc — confirmed both real callers ( |
|||||||||||
| namingStrategy.resolveColumnName(referencedType.getName()) : | |||||||||||
| resolveAssociatedEntityTableName(namingStrategy); | |||||||||||
| var prop = namingStrategy.resolveColumnName(getName()); | |||||||||||
|
matrei marked this conversation as resolved.
|
|||||||||||
| columnName = referencedType.isEnum() ? | |||||||||||
| clazz : | |||||||||||
| new BackticksRemover().apply(prop) + UNDERSCORE + new BackticksRemover().apply(clazz); | |||||||||||
|
|
|||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This returns the table name verbatim, and the two call sites then treat it differently:
joinTableColumNamepasses it throughBackticksRemover, whileresolveJoinTableForeignKeyColumnNameconcatenates_idonto it directly.TableForManyCalculator.calculateTableForManyalso strips backticks fromgetTableName(...), because backtick-quoting a reserved word intableis supported and used (e.g.grails/gorm/tests/multitenancy/Usermapstable 'user').With a quoted table on the far side of a unidirectional
hasMany, the FK column name is now malformed:On 8.0.x the same mapping produces
probe_shelf_user(probe_quoted_id, probe_shelf_quoted_id). Withouthibernate.hbm2ddl.halt_on_errorthe statement fails silently and the join table is simply missing from the generated schema, which makes it an easy one to ship unnoticed.Stripping backticks here (or at the
resolveJoinTableForeignKeyColumnNamecall site, matchingjoinTableColumName) fixes it. A test with a backtick-quotedtablemapping would be worth adding alongside the two new cases.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 546fea4 (pushed before your review, sorry for the noise) — stripped backticks once at the source in
HibernateAssociation#resolveAssociatedEntityTableName, which bothjoinTableColumNameandresolveJoinTableForeignKeyColumnNamego through, so it's no longer left to each caller. Added "resolveJoinTableForeignKeyColumnName strips backticks from a backtick-quoted associated entity table name" reproducing yourtable '\user`'-shaped repro (HTMPQuotedTableAuthor/HTMPQuotedTableBook` in the spec).