ianroberts opened a new issue, #16665:
URL: https://github.com/apache/grails-core/issues/16665
### Expected Behavior
Given a set of domain classes like the following:
```groovy
// Role.groovy
class Role {
String authority
}
// Tag.groovy
class Tag {
String name
String description
}
// Item.groovy
class Item {
String name
static hasMany = [roles: Role, tags: Tag]
}
```
the following sequence of method calls should 1. create an item, 2. create a
role, 3. add a row to the `item_role` join table linking the two
```groovy
def item = new Item(name: "Example item")
item.save(flush: true)
def role = new Role(authority: "ROLE_EXAMPLE")
item.addToRoles(role)
item.save(flush: true)
```
### Actual Behaviour
With Hibernate 5 the join table insert happens as expected, but with
Hibernate 7 it does not - the `Item` and `Role` are created and the second
`item.save` issues the expected SQL `UPDATE` to the `item` table, but it does
_not_ persist the `addToRoles` in the join table.
If I remove the `tags` entry from `hasMany` (so the `Item` class only has
_one_ unidirectional one-to-many association rather than two) then the correct
behaviour is observed on both Hibernate versions.
### Steps To Reproduce
See my [example
repository](https://github.com/ianroberts/grails-h7-multiple-hasmany) - this
has two Grails applications that are identical except that one uses Hibernate 5
and the other uses Hibernate 7. They declare two versions of the `Item` class,
one as above with `static hasMany = [roles: Role, tags: Tag]` and the other
(`UntaggedItem`) with just `static hasMany = [roles: Role]`, and perform the
above steps in `BootStrap` with Hibernate SQL logging enabled
- create the item
- `findOrCreate` the role
- `addToRoles`
- save and flush
On Hibernate 5 both `Item` and `UntaggedItem` log the correct join table
inserts
```
2026-10-17T19:00:35.544+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : ======== Creating Item =========
2026-10-17T19:00:35.628+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : insert into item (id, version, name)
values (default, ?, ?)
2026-10-17T19:00:35.652+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : Created com.example.Item : 1
2026-10-17T19:00:35.653+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : findOrCreate example role
2026-10-17T19:00:35.658+01:00 WARN 1214 --- [ restartedMain]
org.hibernate.orm.deprecation : HHH90000022: Hibernate's legacy
org.hibernate.Criteria API is deprecated; use the JPA
jakarta.persistence.criteria.CriteriaQuery instead
2026-10-17T19:00:35.676+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : select this_.id as id1_3_0_,
this_.version as version2_3_0_, this_.authority as authorit3_3_0_ from role
this_ where (this_.authority=?) limit ?
2026-10-17T19:00:35.679+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : Add role to item
2026-10-17T19:00:35.680+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : Save and flush
2026-10-17T19:00:35.684+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : insert into role (id, version,
authority) values (default, ?, ?)
2026-10-17T19:00:35.736+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : update item set version=?, name=?
where id=? and version=?
2026-10-17T19:00:35.738+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : insert into item_role
(item_roles_id, role_id) values (?, ?)
2026-10-17T19:00:35.740+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : ======== Creating UntaggedItem
=========
2026-10-17T19:00:35.742+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : insert into untagged_item (id,
version, name) values (default, ?, ?)
2026-10-17T19:00:35.743+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : Created com.example.UntaggedItem : 1
2026-10-17T19:00:35.743+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : findOrCreate example role
2026-10-17T19:00:35.743+01:00 WARN 1214 --- [ restartedMain]
org.hibernate.orm.deprecation : HHH90000022: Hibernate's legacy
org.hibernate.Criteria API is deprecated; use the JPA
jakarta.persistence.criteria.CriteriaQuery instead
2026-10-17T19:00:35.744+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : select this_.id as id1_3_0_,
this_.version as version2_3_0_, this_.authority as authorit3_3_0_ from role
this_ where (this_.authority=?) limit ?
2026-10-17T19:00:35.745+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : Add role to item
2026-10-17T19:00:35.745+01:00 INFO 1214 --- [ restartedMain]
com.example.BootStrap : Save and flush
2026-10-17T19:00:35.746+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : update untagged_item set version=?,
name=? where id=? and version=?
2026-10-17T19:00:35.746+01:00 DEBUG 1214 --- [ restartedMain]
org.hibernate.SQL : insert into untagged_item_role
(untagged_item_roles_id, role_id) values (?, ?)
```
On Hibernate 7 only the `UntaggedItem` logs the join table inserts:
```
2026-10-17T19:01:52.908+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : ======== Creating Item =========
2026-10-17T19:01:52.989+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : insert into item (name,version,id)
values (?,?,default)
2026-10-17T19:01:53.019+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : Created com.example.Item : 1
2026-10-17T19:01:53.019+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : findOrCreate example role
2026-10-17T19:01:53.120+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : select
r1_0.id,r1_0.authority,r1_0.version from role r1_0 where r1_0.authority=?
2026-10-17T19:01:53.129+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : Add role to item
2026-10-17T19:01:53.130+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : Save and flush
2026-10-17T19:01:53.135+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : insert into role
(authority,version,id) values (?,?,default)
2026-10-17T19:01:53.157+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : update item set name=?,version=?
where id=? and version=?
2026-10-17T19:01:53.162+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : ======== Creating UntaggedItem
=========
2026-10-17T19:01:53.164+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : insert into untagged_item
(name,version,id) values (?,?,default)
2026-10-17T19:01:53.165+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : Created com.example.UntaggedItem : 1
2026-10-17T19:01:53.165+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : findOrCreate example role
2026-10-17T19:01:53.166+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : select
r1_0.id,r1_0.authority,r1_0.version from role r1_0 where r1_0.authority=?
2026-10-17T19:01:53.166+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : Add role to item
2026-10-17T19:01:53.167+01:00 INFO 1446 --- [ restartedMain]
com.example.BootStrap : Save and flush
2026-10-17T19:01:53.168+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : update untagged_item set
name=?,version=? where id=? and version=?
2026-10-17T19:01:53.169+01:00 DEBUG 1446 --- [ restartedMain]
org.hibernate.SQL : insert into untagged_item_role
(untagged_item_roles_id,role_id) values (?,?)
```
and you can verify with the scaffolded `ItemController` whether the
associations have been saved.
> Note: the test is one `hasMany` vs two, but I am seeing the same issue in
my real app for classes that have three different `hasMany` links, so it does
look like an issue of one vs more-than-one, rather than two vs not-two
### Environment Information
- Operating system: macOS Tahoe 26.6.2
- JDK: Azul Zulu JDK 21
```
openjdk version "21.0.12.1" 2026-08-18 LTS
OpenJDK Runtime Environment Zulu21.52+203-CA (build 21.0.12.1+1-LTS)
OpenJDK 64-Bit Server VM Zulu21.52+203-CA (build 21.0.12.1+1-LTS, mixed
mode, sharing)
```
### Example Application
https://github.com/ianroberts/grails-h7-multiple-hasmany
### Version
8.0.0
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]