0

So, during a bulk data load I'm building a massive tree of domain objects, checking for internal consistency, creating references between them... lots of processing. Then while saving, I'm batching the saves through calling session.clear() every 20 records or so.

My problem is that referenced domain objects are detached from the session when it's clear, so when I try to cascade the save, I get the expected a different object with the same identifier value was already associated with the session

Fragment of the domain model (cascade settings are not explicit in any classes):

class School {
  String name
}

class Room {
  String roomNum
  School school
  static belongsTo = School 
  static hasMany = [teachers:Teacher]
}

class Teacher {
  String name
  Room room
  School school
  static belongsTo = Teacher
  static hasMany = [students:Stuent]
}

class Student {
  String name
  Teacher teacher
  School school
  static belongsTo = Student
}

There are a few more layers, and a lot more breadth to each layer, every Domain carries a reference to "School" for ease of searching. In the service, these objects are all built with a reference to the persisted school.

def buildData() {
 School s = School.get(1)
 Room r = new Room(name: "A", school: s)
 Teacher t = new Teacher(room: r, school: s, name: "Smith")
 r.addToTeachers(t)
 Student s = new Student(teacher: t, school: s, name: "Billy")
 t.addToStudents(s)

 //ad nauseum
}

def persistData() {
  //lots of processing
  def session = sessionFactory.currentSession
  session.flush()
  session.clear()
  ........
  r.save(failOnError:true)
}

r.save() fails, non-unique ID of 1, I can check r.school.isAttached() and it's false. So I change it to...

...
session.clear()
r.school = School.get(r.school.id)
log.info("Attached now?  ${r.school.isAttached()}")  //shows true
r.save(failOnError:true)
}

r.save() fails again, and predictably, r.teacher[0].school.isAttached() is false...

Do I have to manually walk this ridiculous tree and reset every child object's reference to the refreshed "school" object? I feel I must be just missing something or doing something crazy wrong.

Trebla
  • 1,164
  • 1
  • 13
  • 28

2 Answers2

2

As usual, I pound on it enough and look in the right place and I usually figure it out.

Replacing

r.school = School.get(r.school.id)

with

r.school.attach()  

Fixed the problem by re-attaching the in-memory reference rather than loading a new reference and setting the instance of r.school to a different instance. Confirmed this was happening through debugging and looking at the Object numbers.

I thought I had done this in the past and ran into problems when attaching to the session, but I must have been mistaken.

Trebla
  • 1,164
  • 1
  • 13
  • 28
0

Attach works. get is special as it looks locally first in order to avoid a database hit vs load (see below):

Hibernate: Difference between session.get and session.load

Also, findById always works.

Community
  • 1
  • 1
Nathan Dunn
  • 447
  • 5
  • 16