Grails 5.1.7一对多关联domain类集合对象未持久化问题
问题说明
正在开发课程创建类网站,业务逻辑为单个track可包含多个course,每个course又可包含多个assignment。当前现象为:所有领域对象均可单独保存成功,但一对多关联关系未被持久化,映射表TRACK_COURSE和COURSE_ASSIGNMENT中无任何关联数据。
现有代码
领域类定义
- Track类
class Track { String name static hasMany = [courses: Course] static constraints = { name minSize: 2 courses nullable: true } @Override String toString() { return name } }
- Course类
class Course { String name static hasMany = [assignments: Assignment] static belongsTo = Track static constraints = { name nullable: false assignments nullable: true } @Override String toString() { return name } }
- Assignment类
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 } }
Bootstrap初始化代码
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()
问题根因
belongsTo声明方式错误:当前代码中static belongsTo = Track、static belongsTo = Course的写法仅声明了归属关系,未明确指定双向关联的属性名,GORM无法识别父子对象的绑定关系,不会自动维护中间表数据。- 保存逻辑不符合GORM级联规则:配置双向
hasMany+belongsTo关联后,仅从父对象端发起的保存操作会级联持久化所有关联对象和关联关系,代码中单独保存course、assignment的操作属于冗余操作,且保存顺序混乱,会打断GORM的级联关联持久化流程。 - 无效配置干扰:
hasMany声明的集合类型属性默认初始化为空集合,永远不会为null,在constraints中给courses、assignments配置nullable: true属于无效配置,会干扰GORM的映射判断。 - 未开启错误抛出:默认
save()方法会静默吞掉校验、关联持久化的错误,仅打印track.getErrors()无法捕获子对象、关联关系的保存异常。
修复方案
- 修正领域类的
belongsTo声明,明确关联属性名:- Course类中修改为
static belongsTo = [track: Track] - Assignment类中修改为
static belongsTo = [course: Course] - 删除constraints中给
courses、assignments配置的nullable: true规则
- Course类中修改为
- 调整初始化代码逻辑,删除冗余的子对象单独保存操作,从根对象发起级联保存,开启错误抛出方便排查问题:
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") course.addToAssignments(assignment1).addToAssignments(assignment2) Track track = new Track(name: "Practices") track.addToCourses(course) // 仅保存最上层track即可,级联规则会自动保存所有关联的course、assignment并写入中间表关联数据 track.save(failOnError: true, flush: true)
修复后重启应用,重新执行初始化逻辑即可看到
TRACK_COURSE、COURSE_ASSIGNMENT表中正确写入关联数据。
内容的提问来源于stack exchange,提问作者Sap
相关产品推荐
相关产品推荐

