2

I'm having troubles with a table having a table having a many to many relationship to itself since a requirement can have multiple parents and multiple children. I basically created entities from database using NetBeans wizards and everything else seems to work fine. But doing unit tests for this parent/child relationship I started having failures. Basically, when I add a child to a requirement somehow the child ends up having the parent as a child as well.

I believe is somehow related to the JoinTable having 2 columns pointing to the same key.

Here's the relevant entity code mapping this:

@JoinTable(name = "requirement_has_requirement", joinColumns = {
    @JoinColumn(name = "requirement_id", referencedColumnName = "id"),
    @JoinColumn(name = "requirement_version", referencedColumnName = "version")}, inverseJoinColumns = {
    @JoinColumn(name = "parent_requirement_id", referencedColumnName = "id"),
    @JoinColumn(name = "parent_requirement_version", referencedColumnName = "version")})
@ManyToMany
private List<Requirement> requirementList;
@ManyToMany(mappedBy = "requirementList")
private List<Requirement> requirementList1;

Database Design

If needed, the code can be obtained here: https://javydreamercsw@bitbucket.org/javydreamercsw/validation-manager

Edit The questions are hard to answer, since in reality it doesn't work. In theory requirementList should have child and requirementList1 the parent of the relationship.

When I try to add a child I do something like:

requirement.getRequirementList().add(requirement2);
<Persist requirement here>

Assuming the two requirements are proper valid entities.

javydreamercsw
  • 5,363
  • 13
  • 61
  • 106
  • Is it the many to many association the one you are talking about when you say "parent child"? – mwhs Nov 20 '13 at 17:02
  • It is probably in your `@JoinTable` annotation. You can cause for JPA to generate entries in the database that do not represent the desired relationship this way. They would look right before you commit, but then be wrong when you fetch them again. – le3th4x0rbot Nov 20 '13 at 17:05
  • Where in the bitbucket repo are the entities? – mwhs Nov 20 '13 at 17:14
  • @mwhs: Yes, is the many to many. – javydreamercsw Nov 20 '13 at 17:19
  • The link directly to entities: https://bitbucket.org/javydreamercsw/validation-manager/src/0cdb420f35591c6c891fa2a33ee9dbc538ed4a19/VM-Core/src/main/java/com/validation/manager/core/db/?at=default – javydreamercsw Nov 20 '13 at 17:21
  • In each entity class of yours that I have seen, also in the embeddable types (PK), the Serializable interface is implemented and the method hashcode and equals are overwritten. What is the purpose? This is not required by the JPA specification. It might in fact lead to strange behaviour in collection handling in JPA, since the implementations rely on object identity. – mwhs Nov 20 '13 at 21:55
  • Hmmm, all that was created by the Netbeans wizard. Never had issues with those before. I'll remove those and give it a try – javydreamercsw Nov 21 '13 at 16:31
  • Please update your question, by showing&renaming which of the properties contain the children and which the parents and also by showing us how you add a child to a requirement. – V G Nov 21 '13 at 20:10

1 Answers1

1

I suppose the problem is that you add the child to the wrong side of the relationship (you do not update the relationship correctly), depending who is the child in that relationship. As of the persistence part, you must add it to the owning side of the relationship, specifically to the property requirementList. On the other side, your duty is also to update correctly ALSO the not-owning part (the requirementList1).

So try the following:

Requirement requirementToUpdate = em.find(Requirement.class, pk);//replace pk with your PrimaryKey value
Requirement newRequirement = new Requirement();//fill in the properties

newRequirement.getRequirementList1().add(requirementToUpdate);//this is very important for your code
requirementToUpdate.getRequirementList().add(newRequirement);//this is very important for persistence
em.persist(newRequirement);//this should not insert anything in the 'requirement_has_requirement' table
em.persist(requirementToUpdate);//this should update the 'requirement_has_requirement' table

For an excerpt from the JPA specification related to updating bilateral relationships, see this answer.

Also you might consider adding some Cascading (specifically on persist and merge).

For implementing the equals()/hashCode() in JPA, check this answer, although leaving the default Object implementation would suffice to see if that is the cause of your problem.

Community
  • 1
  • 1
V G
  • 18,822
  • 6
  • 51
  • 89