CodeMed
CodeMed

Reputation: 9189

not saving child entity

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

Answers (1)

Learner
Learner

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

Related Questions