I'm working on a project where we have two copies of entities in the database, with different tables (it uses two persistence units with the same classes, but a mapping file with different table names for one of them). There's a working copy and live data. Changes to the working copy can be applied in the live data, but can also be undone. Any entities created in the working copy must be deleted, any entities updated must be made consistent with the live data again.
An edit can specify whether it will update its direct target or not. If it only updates descendants in the entity hierarchy, or creates some new descendants, the "target" entity isn't directly changed and doesn't have to be synced with the live data again. This is important, because undoing an edit can result in other edits being undone/deleted as well if they happen to affect the same entities. I'd like to minimize such "side-effects" to the extent possible.
Suppose we have a Course
class that can have any number of Students
. I want the relation to be bidirectional. The course has a collection of students and specifies "mappedBy" in the @OneToMany
annotation.
@Entity
public class Course {
// Primary key and other fields would be here...
@OneToMany(mappedBy = "course", fetch = FetchType.LAZY)
private List<Student> students;
// Getters, setters...
}
The student class is the owning side from database perspective (it will have the foreign key to the Course table) and specifies a @JoinColumn
.
@Entity
public class Student {
// Primary key and other fields...
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "course_id")
private Course course;
// Getters and setters...
}
No operations are cascaded. Not MERGE, PERSIST, REMOVE... or anything. Because of the way the whole thing operates such things are handled by the edit framework. The whole thing runs in Java EE and transactions are handled by the container.
An edit might create a new student and add it to a course. So for example:
Course course;
// Fetch the course from persistence
Student student = new Student("John Doe");
student.setCourse(course);
course.getStudents().add(student);
In order to keep the data model consistent, the course is set for the student, and the student is also added to the list in the course. The course_id
column is properly filled in upon persisting the student.
If the edit is not applied to the live data but undone, the student entity that was created must now be deleted. The question that arises then is how to regard the course. In a sense it was updated, because something got added to its collection. However, no change had to be made in the database for the course. Its not the owning side of the relationship in the RDBMS. If we have the course synced up from the live data, other changes to the course might need to be undone or deleted. If we don't, they may be able to remain.
Suppose I'm in a JTA transaction and have an entity manager injected. If I fetch the student from it and perform the remove operation on it, I don't suppose I need to fetch the course explicitly and remove the student from the collection.
Questions:
Assume the only thing that's gonna happen in the transaction and for the persistence context within it is the deletion/syncing of such entities, so that the collection would be inconsistent for a short while on the Java side is not really an issue. If it contains an entity that had to be deleted the framework code will take it into account, and the objects aren't kept around longer than for the transaction.
Your assumptions are correct. Since no operations are cascaded from Course
to Student
, and Course
is not the owning side, the JPA provider will ignore changes (and absence of changes) in the students
collection.
However, if second-level cache is enabled for the students
collection, then you would need to remove the deleted student from the collection as well so that changes are reflected in the cache.