I got OneToMany relationship between school and student entities. What I want to do is when I save a school object don't save or update students object.(and of course don't delete them)
When I try to save school object like below it also updates my student objects but I don't want them to be updated but only jointable. Is there any way?
I removed Cascade but its still not working.
School school = new School();
school.setStudents(studentList);
repository.save(school);
My Entity;
@OneToMany(fetch = FetchType.EAGER)
@JoinTable(name = "school_student", joinColumns = {@JoinColumn(name = "school_id")},
inverseJoinColumns = {@JoinColumn(name = "student_id")})
private List<Student> students;
EDIT:
When I try to save school object like below it also updates my student objects but I don't want them to be updated but only jointable. Is there any way?
I think you mean that you want the association itself to be managed -- i.e. which students are associated with the school -- but not the student details. This does not make much sense, I'm afraid, for both conceptual and practical reasons.
Conceptually, the "owning" side of a one-to-many relationship is always the "many". This is a bit arbitrary (but nevertheless still true) when you manage the association via a join table, but it is important when the association is managed directly via entity attributes. Updating the association requires managing the entities on the owning side, which in this case is your Student
s.
As a practical matter, managing the association from the School
side only would raise some difficulties. For example, what if a new Student
is added to a School
? That student needs to be persisted before the association can be persisted, but you want to avoid that happening. There is a similar, but lesser, problem when you move a Student
from one School
to a different one.
Now, you can indeed avoid cascading persistence operations from School
s to their Student
s, but I would expect the result of doing so to be failure to manage the association between them in conjunction with managing School
s. If that's what you want to do, then you would omit any cascade
attribute from the @OneToMany
annotation, or else explicitly specify an empty list of cascade types.
Note also, however, that changes to all persistent entities are saved when you commit changes to your persistence context. If you want to modify Student
entities without having those changes be saved to the database, then your best alternative is probably to detach those entities, or else to make detached copies of them.
Update:
As has been clarified in comments, the essential problem is how to modify the relationship between School
and Student
entities when the application does not have permission to update the base table of Student
, but does have sufficient permissions on the join table by which the relationship is represented. You cannot do this automatically in conjunction with persisting changes to School
s, because School
is not -- and cannot be -- the owning side of the relationship.
To clarify: JPA is attempting to save your Student
entities when you move them to different School
s because for its purposes, the association between a Student
and his particular School
is part of the state of the Student
. If the Student
entity is attached to the persistence context and is dirty (e.g. because it was assigned to a different School
), then it will be updated when changes to the PC are committed. This has nothing in particular to do with cascading or with the state of the School
, except that you modify the states of your Student
s indirectly by moving them to different School
s' students
lists.
Since you are using a join table, you could modify your object model to represent each student / school association as an entity in its own right. That would make sense if those associations had attributes of their own, such as enrollment dates, but otherwise I wouldn't recommend it.
The alternative is to write native queries (via JPA); you'll find lots of information about that around the net, such as https://blogs.oracle.com/JPQL01/entry/native_query_in_java_persistence. This does introduce some problems, however. In particular, it invalidates the EntityManager
's cache, which can produce serious problems if not dealt with. It may also be significant to you that it produces entity changes without triggering the entity lifecycle methods that would fire if you performed the update normally.
With respect to the cache, the solution is to detach the affected Student
and School
(both old and new) entities. You can do that selectively with EntityManager.detach()
, or en masse with EntityManager.clear()
. Afterward, you'll need to re-query or merge the entities you want to continue using, and that could make for some messy problems, depending on how pervasively they are used and on what assumptions other code makes about them.
As for the lifecycle methods, if you need to ensure they fire, then you have the alternative of invoking them yourself.
This article provides a few more details on what you might need to do.
Perhaps you can try @JoinColumn:
@OneToMany
@JoinColumn(name = "school_id", updatable = false, insertable = false)
private List<Student> students;
The structure you're showing us is not a One-To-Many relation as you've listed. It's Many-To-Many.
@ManyToMany(cascade = {}, targetEntity = Student.class)
@JoinTable(name = "school_student", joinColumns = {
// references column "id" of "school"
@JoinColumn(name = "school_id", referencedColumnName = "id")
}, inverseJoinColumns = {
// references column "id" of "student"
@JoinColumn(name = "student_id", referencedColumnName = "id")
})
private List<Student> students;
It's really that simple.
remove these annotations
@OneToMany(fetch = FetchType.EAGER)
@JoinTable(name = "school_student", joinColumns = {@JoinColumn(name = "school_id")},
inverseJoinColumns = {@JoinColumn(name = "student_id")})
So hibernate entity manager may not associate this object to update automatically
So you have to write manual query to students in set method or pass list of students as argument in your code logic to set students
private List<Student> students;
then it will work as you expected
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With