Search code examples
grailsgrails-ormgrails-domain-class

Grails domain class does not add collection objects in one to many mapped classes Grails 5.1.7


I am working on a course creator website where a track can have multiple courses and they in turn, can have multiple assignments

The domain classes are defined as the following.

class Track {
String name
static hasMany = [courses: Course]
static constraints = {
    name minSize: 2
    courses nullable: true
}

@Override
String toString() {
    return name
}
}

and

class Course {
String name
static hasMany = [assignments: Assignment]
static belongsTo = Track
static constraints = {
    name nullable: false
    assignments nullable: true
}

@Override
String toString() {
    return name
}
}

and

class Assignment {
String name
String description
String url
static belongsTo = Course
static constraints = {
    name nullable: false
    description minSize: 20, widget: 'textarea'
    url nullable: true, url: true
}

@Override
String toString() {
    return name
}
}

While the final goal is to make a many to many relationship.

The bootstrap.groovy file has the following code.

        Assignment assignment1 = new Assignment(name: "Read Software Craftsman", description: "Software Craftsman " +
                "by Sandro Mancuso is one of the mandatory readings at Incubyte",
                url: "https://www.amazon.in/s?k=software+craftsmanship&sprefix=software+craftsman%2Caps%2C231&ref=nb_sb_ss_ts-doa-p_1_18")

        Assignment assignment2 = new Assignment(name: "Read Clean Coder", description: "Principles of clean coding is vital for the code readability. ",
                url: "https://www.amazon.in/Clean-Coder-Robert-C-Martin/dp/813178696X/ref=sr_1_1?crid=187IC46P73OZ7&keywords=clean+coder&qid=1654424906&sprefix=clean+coder%2Caps%2C451&sr=8-1")

        Course course = new Course(name: "Values and Practices of Software Development")
        Track track = new Track(name: "Practices").addToCourses(course)
        course.addToAssignments(assignment1).addToAssignments(assignment2)
        track.save()
        course.save()
        assignment1.save()
        assignment2.save()
        println track.getErrors()

While each one of the domain objects is being saved successfully, one to many relationship is not being persisted, and thus mapping tables TRACK_COURSE and COURSE_ASSIGNMENT have no data.


Solution

  • While each one of the domain objects is being saved successfully, one to many relationship is not being persisted, and thus mapping tables TRACK_COURSE and COURSE_ASSIGNMENT have no data.

    I cannot reproduce that but the project at https://github.com/jeffbrown/sapgormrelationships may help you.

    I have pasted your code directly from the question into that project. At startup you will see the following written to stdout:

    Hibernate: insert into track (id, version, name) values (default, ?, ?)
    Hibernate: insert into course (id, version, name) values (default, ?, ?)
    Hibernate: insert into assignment (id, version, url, name, description) values (default, ?, ?, ?, ?)
    Hibernate: insert into assignment (id, version, url, name, description) values (default, ?, ?, ?, ?)
    org.grails.datastore.mapping.validation.ValidationErrors: 0 errors
    Hibernate: insert into track_course (track_courses_id, course_id) values (?, ?)
    Hibernate: insert into course_assignment (course_assignments_id, assignment_id) values (?, ?)
    Hibernate: insert into course_assignment (course_assignments_id, assignment_id) values (?, ?)
    

    You can see inserts into both course_assignment and track_course. You can also validate that the data is there by interacting with the default scaffolding pages in the app.

    grails-app/init/sapgormrelationships/BootStrap.groovy#L14-L30

    @Transactional
    void populateData() {
        Assignment assignment1 = new Assignment(name: "Read Software Craftsman", description: "Software Craftsman " +
                "by Sandro Mancuso is one of the mandatory readings at Incubyte",
                url: "https://www.amazon.in/s?k=software+craftsmanship&sprefix=software+craftsman%2Caps%2C231&ref=nb_sb_ss_ts-doa-p_1_18")
    
        Assignment assignment2 = new Assignment(name: "Read Clean Coder", description: "Principles of clean coding is vital for the code readability. ",
                url: "https://www.amazon.in/Clean-Coder-Robert-C-Martin/dp/813178696X/ref=sr_1_1?crid=187IC46P73OZ7&keywords=clean+coder&qid=1654424906&sprefix=clean+coder%2Caps%2C451&sr=8-1")
    
        Course course = new Course(name: "Values and Practices of Software Development")
        Track track = new Track(name: "Practices").addToCourses(course)
        course.addToAssignments(assignment1).addToAssignments(assignment2)
        track.save()
        course.save()
        assignment1.save()
        assignment2.save()
        println track.getErrors()
    }
    

    You have not provided enough information to know for sure, but I suspect that a transaction isn't being properly managed. If you remove @Transactional from my example, I expect you may see the same behavior you reported above.