Search code examples
grailsgrails-orm

Index out of bound when use data binding to update many-to-many relation


I have problem for updating domain that has many-to-many relation. For instance, consider these 2 simple domains.

class Student {
   String name
   static hasMany = [courses: Course]
}

class Course {
  String name
  static hasMany = [students: Student]
  static belongsTo = [Student]
}

To update student's name along with his/her courses' name, I use data binding like this:

def params = [
  'courses[0].id': c2.id,
  'courses[0].name': 'c11',
  'courses[1].id': c1.id,
  'courses[1].name': 'c22'
]
s1.properties = params
s1.save(flush: true)

However, this will cause error:

org.springframework.beans.InvalidPropertyException: Invalid property 'courses[1]' of bean class [tb.Student]:
Invalid list index in property path 'courses[1]'; nested exception is java.lang.IndexOutOfBoundsException:
Index: 1, Size: 1

After some searching, I found that all answers suggest to use List for relation instead of Set. However, I still prefer to use Set.

Environment

  • Grails: 2.2.3
  • Java: 1.6.0_45
  • OS: Ubuntu 13.04

Solution

  • My solution is to clear the children list before data binding. This is the full code to test above domains. The line s1.courses.clear() will prevent above error.

    def s1 = new Student(name: 's1').save(flush: true)
    def s2 = new Student(name: 's2').save(flush: true)
    def c1 = new Course(name: 'c1').save(flush: true)
    def c2 = new Course(name: 'c2').save(flush: true)
    s1.addToCourses(c1)
    s1.addToCourses(c2)
    s1.save(flush: true)
    def params = [
      'courses[0].id': c2.id,
      'courses[0].name': 'c11',
      'courses[1].id': c1.id,
      'courses[1].name': 'c22'
    ]
    s1.courses.clear()
    s1.properties = params
    s1.save(flush: true)
    

    However, I still think this problem is a bug. And my solution is a work around.