简体   繁体   中英

JPA/Hibernate relation working in one direction

I've got many to many relation between my tables parents and children.

This is the part from the Parent class which maps this relation :

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "parents_children", 
            joinColumns = { @JoinColumn(name = "PARENT_ID", nullable = false, updatable = false) }, 
            inverseJoinColumns = { @JoinColumn(name = "CHILD_ID", nullable = false, updatable = false) })
protected Set<Child> children = new HashSet<Child>();

Here is the part in my Child class :

@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER, mappedBy = "children")
protected Set<Parent> parents;

Now this works from the parent side when I try to add children, if I had one Child object defined as child and one Parent object defined as parent :

parent.getChildren().add(child);

This updates correctly in db and it saves the entry to parents_children table.

However when I try to do it from the other end, from children I want to setParent(s). If I had Set<Parent> parents defined and I had updateParents() method defined inside my Children class and I had one child loaded from db defined as child and I tried this :

public void updateParents() {
    Set<Parent> parents = //get this from somewhere

    child.setParents(parents);
    update();
}

This will not work and I'm trying to figure out why. It will work if I modify my method to :

public void updateParents() {
  Set<Parent> parents = //get this from somewhere

  for (Parent parent : parents) {
    parent.getChild().add(this);
  }
}

Am I doing something wrong with relation definition? I haven't use Java in a while and I'm having trouble with remembering this one.

Can someone point out to me what am I doing wrong so I can add parents to children objects?

No, there's nothing wrong with your definition. The problem is that children is the owning side of the association and unless you add the child to that set the database will not be updated.

You could change parents to map the same table, ie remove the mappedBy and thus effectively use two uni-directional associations, but that might cause problems when parents and children are updated.

Consider this case:

  • Object A has children B and C
  • Object B has parent A
  • Object C has no parent (A is not in the parents set)

You now update A and C. Should C still be a child of A or not? The information is contradictory.

To resolve this, only one side should be responsible for updating the relation, which in your case would be A (by its children set).

In JPA your responsible for managing both sides of an association. This means that you must explicitly set a field on the one side of the relationship and add an element to a collection on the many side.

For example, consider a Student entity with a field List<Course> and assume a bidirectional OneToMany / ManyToOne relationship exists between both entities, Student and Course .

When adding a Course for a Student you would manage the relationship such as:

Course course = //findFromSomewhere;
Student student = //findEntity;

course.setStudent(student);
student.getCourses().add(course);

When persisting from the inverse side of the relationship you would manage the entities in the same way.

   course.setStudent(student);
   student.getCourses().add(course);

Just because you insert/update a field on one entity does not mean that Hibernate/JPA will automatically update the other side of the relationship for you. Persisting like this would not update the other side of the association:

   //This would fail to add the course to the students list of courses.
   course.setStudent(student);
   em.persist(course);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM