Reputation: 9189
In a spring mvc project using hibernate and jpa, I am have a person
entity, and a role
entity. Each person
can have many roles
, but each role
can only have one person
. How can I save a new role
for an existing person
?
I have read many postings on this. If I try to save the new role
, I get an error about not being able to save a detached entity. But if I try to save the existing person
, the role does not get saved. I read this posting suggesting that the hibernate annotations should be moved to the getters, but when I do that, I get a hibernate mapping error referencing an unknown property. And this posting says the resolution of the new error is to move the annotations back to the getters, without mentioning that results in the detached entity error. The various stack overflow questions thus seem to point in a circle. So how can I fix my code to actually save the new child entity?
Here is the Person:
@Entity(name = "RimPerson")
@Table(name = "rim_person")
public class RimPerson {
@Id
@Column(name="hppid")
@GenericGenerator(name = "generator", strategy = "native")
@GeneratedValue(generator = "generator")
private Long hppid;
@OneToMany(targetEntity = RimRole.class, cascade = {CascadeType.ALL
}, fetch = FetchType.EAGER)
@JoinColumn(name = "player_rimperson_HJID")
private List<RimRole> playedRoles;
//other properties and getters and setters
}
Role is:
@Entity(name = "RimRole")
@Table(name = "rim_role")
public class RimRole {
@Id
@Column(name="hppid")
@GenericGenerator(name = "generator", strategy = "native")
@GeneratedValue(generator = "generator")
private Long hppid;
@ManyToOne(targetEntity = RimPerson.class, cascade = {CascadeType.ALL
}, fetch = FetchType.LAZY)
@JoinColumn(name = "player_rimperson_HJID", nullable=true)
private RimPerson player;
//other stuff and getters and setters
}
Here is the JPQL in the repository layer:
@Override
public void saveRIMPerson(RimPerson myperson) throws DataAccessException{
if (myperson.getHppid() == null) {this.em.persist(myperson);}
else {this.em.merge(myperson);}
}
The complete code for the relevant classes can be found at this link.
Upvotes: 0
Views: 2111
Reputation: 21393
You have a bi-directional one-to-many relationship between entities RimPerson
and RimRole
. So you need to tell hibernate which is the owner of association using the mappedBy
attribute, in case of one-to-many
relationship the many
side is considered as owner of association, so in RimPerson
the mapping should be like this:
@OneToMany(targetEntity = RimRole.class, mappedBy="player", cascade = {CascadeType.ALL
}, fetch = FetchType.EAGER)
private List<RimRole> playedRoles;
Note that we have to remove the @JoinColumn
annotation from here. Also the value of mappedBy attribute should match with the property name that you have defined in RimRole
which is player
.
Now for a bi-directional association you need to set the properties from both sides of entities, this means:
rimPerson.setPlayedRoles(playedRoles);
rimRole.setPlayer(player);
Try to update your code with these changes and run the application, this should fix the issue.
Upvotes: 1