apache / apache/grails-core

many-to-many associations misbehave when the belongsTo property is missing. No errors, but no data is saved.

Open
#14,358 0 comments 0 reactions 0 assignees View on GitHub
relates-to: gorm
Dominant language
Groovy
Stars
2.9k
Forks
975
Avg merge
1d 22h
Merged PRs (30d)
92

Description

### Task List

- [X] Steps to reproduce provided
- [X] Stacktrace (if present) provided
- [X] Example that reproduces the problem uploaded to Github
- [X] Full description of the issue provided (see below)

### Steps to Reproduce

1. Create two domain classes with a hasMany relationship between the two
2. Try and save a relationship

### Expected Behaviour

Either an exception should be thrown warning that the many-to-many is misconfigured. (old grails 2 behavior).
Or the relationship data should be saved. (perhaps modeled as two different one-to-many relationships and two different join tables).

### Actual Behaviour

No exception is thrown.
In Memory relationship data is stored, and back references are set up along with back references.
No relationship data is stored.

### Environment Information

- **Operating System**: windows/linux
- **GORM Version:** 7.3.2
- **Grails Version (if using Grails):** 5.2.3
- **JDK Version:** 1.8

### Example Application

https://github.com/tircnf/manytomany

The only real file in the project is a hibernateSpec. The Spec contains two entities with one-to-many mappings to each other.

``` groovy
@Entity
class Person {
String name
static hasMany = [pets: Pet]
}

@Entity
class Pet {
String name
static hasMany = [owners: Person]
}
```

Here is the test that shows the problem.
``` groovy
void "Expect associations work"() {
given: "A Person and Pet"
Person steve = new Person(name: "steve").save(flush:true, failOnError:true)
Pet spot = new Pet(name: "spot").save(flush:true, failOnError:true)

when: "I associate them"
steve.addToPets(spot)
println "Saving... updates the version number on both person and pet, but doesn't write the association data"
steve.save(flush:true, failOnError:true)
println "Flush done."

then: "It got persisted in memory"
steve.pets.size()==1
steve.pets[0].name=="spot"

and: "back references are set up"
spot.owners.size()==1
spot.owners[0]==steve

when: "if I reload from database"
sessionFactory.currentSession.clear()
Person steve2 = Person.get(steve.id)

then: "those relationships are gone"
steve2.pets.size()==1
steve2.pets[0].name=="spot"
}
```

I discovered this when I inadvertently tried to create two separate one-to-many relationships between two domain Classes. I was not looking to set up a many-to-many.

My original test didn't clear the session, so loaded the domain items from the hibernate cache, and they still had accesses to the relationships. After the session was cleared the associations just disappeared.

with sql logging turned on, you can verity that even though person/pet are getting the versions updated, no relationship data is stored.

At the very least having the old exception
`No owner defined between domain classes [class manytomay.Person] and [class manytomay.Pet] in a many-to-many relationship. Example: static belongsTo = manytomay.Pet`

would have made my error really obvious.

Contributor guide

Open the contributing guide

Research direction

Start with the hibernateSpec in the linked manytomany example application and run the association test using the Person and Pet domain classes. Inspect what happens after the session is cleared: done should mean either the missing belongsTo configuration raises a clear exception or the association is persisted and reloads from the database.

Written by the indexing model from the issue text.

Assessment

Tech stack
groovy
Domain
database
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.