0

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.

Community
  • 1
  • 1
CodeMed
  • 9,527
  • 70
  • 212
  • 364

1 Answers1

1

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.

Chaitanya
  • 15,403
  • 35
  • 96
  • 137
  • Your code triggered a new error before I can get to the point to test your code. I will look into this again in 12 hours. It is late here. But the new error triggered by your code is: `java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: RimPerson is not mapped [SELECT pers FROM RimPerson pers left join fetch pers.names WHERE pers.hppid =:id]` – CodeMed Nov 11 '14 at 05:53
  • The error says hibernate doesn't know what `RimPerson` is, this is not possible based on the explanation in your question. Please post your `hibernate.cfg.xml` file, code that you have tried and complete stacktrace of exception once you have access to your machine at your day time, so I can check further. – Chaitanya Nov 11 '14 at 06:03
  • +1 Thank you. The follow up error was due to my having renamed the package in a way that made spring unable to find it unless a changed a config file. Your suggestion helped me isolate that cause. It works now. – CodeMed Nov 11 '14 at 18:09