[coldbox-3.8.1] ORM - Deleting multiple related entities in the same request

Hey all, something just didn’t feel right about my “final solution” so I thought I’d throw it out to the community. I think honestly what didn’t feel right is that it took an entire day to get to something that even worked…so now I’m just hoping it’s a somewhat accepted solution :slight_smile:

Let’s say I’ve got three persistent entities, Course, Student and CourseStudent.
Related like this: *Course <*one-to-many> *CourseStudent <*many-to-one> Student

And here are the entity models:

Course
`
component persistent=“true” table=“Course” {

property name=“ID” fieldtype=“id” column=“ID” generator=“native” setter=“false”;
property name=“courseName” column=“CourseName” ormtype=“string”;
property name=“courseCode” column=“CourseCode” ormtype=“string”;

// Relationships
property name=“courseStudents” fieldtype=“one-to-many” cfc=“CourseStudent” fkcolumn=“CourseID” type=“array” singularname=“courseStudent” inverse=“true” cascade=“delete”;
}
`

Student

`
component persistent=“true” table=“Student” {

property name=“ID” fieldtype=“id” column=“ID” generator=“native” setter=“false”;
property name=“name” column=“Name” ormtype=“string”;
property name=“email” column=“Email” ormtype=“string”;

// Relationships
property name=“courseStudents” fieldtype=“one-to-many” cfc=“CourseStudent” fkcolumn=“StudentID” type=“array” singularname=“courseStudent” inverse=“true” cascade=“delete”;
}
`

CourseStudent
`
component persistent=“true” table=“CourseStudent” {

property name=“ID” fieldtype=“id” column=“ID” generator=“native” setter=“false”;
property name=“courseID” column=“CourseID” ormtype=“string”;
property name=“studentID” column=“StudentID” ormtype=“string”;
property name=“enrollDate” column=“EnrollDate” ormtype=“timestamp”

// Relationships
property name=“course” fieldtype=“many-to-one” cfc=“Course” fkcolumn=“CourseID”;
property name=“student” fieldtype=“many-to-one” cfc=“Student” fkcolumn=“StudentID”;}
`

Because I have cascade=“delete” set on the Course and Student entity relationship to CourseStudent, if I delete a Course OR Student object it will also delete any related object from CourseStudent. This is good! If a student is deleted then I don’t want records hanging around about any courses they were enrolled in. If a course was deleted then I don’t need to have data about which students were in that course.

BUT, if in the same request I want to remove a specific single Course AND all related student objects (related through CourseStudent)…what is the best way to do that? Essentially I want to remove records from all three tables in the same request/process.

What I settled on was the deleteCourse() function below:
CourseService.cfc
`
component extends=“coldbox.system.orm.hibernate.VirtualEntityService” singleton {

// Dependency Injection
property name=“courseService” inject=“entityService:Course”;
property name=“studentService” inject=“entityService:Student”;

// Constructor
CourseService function init(){
super.init(entityName=“Course”);
return this;
}

function deleteCourse(Course aCourse) {

if (aCourse.hasCourseStudent()) {
var courseStudents = aCourse.getCourseStudents();

// Process array in reverse order
// or else madness ensues with array index reordering after each delete
for(var i = ArrayLen( courseStudents ); i >= 1; i–) {
// Delete this Student
studentService.delete(courseStudents[i].getStudent());

// Disassociate this CourseStudent from the Course
// or else Hibernate will throw synchronization errors when trying to delete the CourseStudent objects again
aCourse.removeCourseStudent(courseStudents[i]);
}
}

// Now, delete the course. All associated CourseStudent entities
// should have already been deleted (cascaded) when the Students were deleted above.
courseService.delete(aCourse);
}
}
`

I had two major problems before arriving at the above solution

  1. I kept getting Hibernate errors about the model not being properly synchronized – obviously I didn’t do something to keep the in-memory version of these objects in sync with the database as I was processing the delete commands. That something (I thnk) was to remove the relationship to the CourseStudent object from the Course as I was deleting each Student. Otherwise when the command ran to delete the Course it would also try to delete those same CourseStudent objects that were already deleted (via cascade=“delete”) when the Students were deleted. I don’t know if there is a better way to keep things in sync or not…but I tried a lot of ways that didn’t work.
  2. When I was looping through the courseStudents array and deleting the associated students, the array kept reindexing every time I removed the item at position “1”. So I’d delete item “1”, then iterate to item “2”, however in between, the array would reindex and move what I thought was item “2” to be in position “1”. Since I was then at position “2” it would have the effect of skipping that record and every second record down the line. The solution it seemed was to process the array in reverse order.

Is there a better way to tackle this or anything that looks odd to anyone else? I’m definitely open to learning…

Thanks for your neurons!

Wes