JPA中的@OneToMany关系无法正常工作

时间:2019-03-25 10:50:11

标签: jpa java-ee entity

嗨,我有以下关系:

@Entity
public class Athlete implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer athleteId;

    @ManyToOne
    @JoinColumn(name="closetWaiting")
    private Closet closetWaiting; 
....

 @Entity
public class Closet implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer closetId;

    @OneToMany(mappedBy="closetWaiting")
    private List<Athlete> waitingList;
 ....

在我的Bean类中,我有以下代码:

  public void addAthleteIntoWaitingList(String closetId, Athlete singleAthlete ) {
        Closet singleCloset=entityManager.find(Closet.class,Integer.parseInt(closetId));

        List<Athlete> waitingList=singleCloset.getWaitingList();        
        waitingList.add(singleAthlete);     
        singleCloset.setWaitingList(waitingList);

        singleAthlete.setClosetWaiting(singleCloset);
    }

不起作用,因为在我调用方法addAthleteIntoWaitingList之后,表Athlete中的CLOSETWAITING列始终为空。

我在这里做错什么了吗?有解决方案的建议吗?

编辑:

为了理解代码背后发生的事情,我在persistence.xml中激活了eclipse的日志记录属性。所以这是我调用该方法时得到的:

2019-03-26T10:37:16.862+0100|Fein: SELECT ATHLETEID, FIRSTNAME, GENDER, LASTNAME, PHONENUMBER, closetWaiting FROM ATHLETE WHERE (ATHLETEID = ?)
    bind => [12]
2019-03-26T10:37:16.871+0100|Fein: SELECT CLOSETID, CLOSETRANK, GENDER, ISBROKEN, ISOCCUPIED, RESERVATIONENDED, RESERVATIONSTARTED, athleteId FROM CLOSET WHERE (CLOSETID = ?)
    bind => [5]
2019-03-26T10:37:16.876+0100|Fein: SELECT CLOSETID, CLOSETRANK, GENDER, ISBROKEN, ISOCCUPIED, RESERVATIONENDED, RESERVATIONSTARTED, athleteId FROM CLOSET

这意味着JPA正在获得Id = 12的运动员,然后找到Id = 5的壁橱。但是随后,它完全忽略了将运动员添加到waitingList中的其余代码,并且不会将其持久化到数据库中。

现在显示真正的问题是为什么会这样?

解决方案:

除了@Peter的解决方案效果很好之外,我进行了以下更改,而未添加任何层叠类型,更重要的是,没有调用merge方法:

我更改了我的方法获取对象“运动员”的方式。我没有通过提供它作为参数,而是通过EJB Bean中的EntityManager.find()获取了它。这是它的外观:

public void addAthleteIntoWaitingList(String closetId, String athleteId ) {
    Closet singleCloset=entityManager.find(Closet.class, Integer.parseInt(closetId));

    Athlete singleAthlete=entityManager.find(Athlete.class, Integer.parseInt(athleteId));

    List<Athlete> waitingList=singleCloset.getWaitingList();        
    waitingList.add(singleAthlete);     
    singleCloset.setWaitingList(waitingList);

    singleAthlete.setClosetWaiting(singleCloset);
}

有人可以向我解释为什么这行得通吗?我猜是因为我在事务内部是否操纵了Ahtlete对象?

2 个答案:

答案 0 :(得分:1)

如果保存父实体,没有@OneToMany(cascade=CascadeType.ALL)集合将不会保存。

如果您在事务中更改实体属性,则无需显式调用合并。如果实体不在交易范围之内,则它将被删除。分离的实体为singleAthlete。需要合并。 容器退出最后一个EJB方法会自动提交事务。

显式调用entityManager.merge(closet)。

答案 1 :(得分:0)

我认为在将“ singleAthlete”添加到列表之前,必须将其保存到数据库,因此在waitingList.add(singleAthlete)之前尝试: entityManager.persist(singleAthlete); 当然,不要忘记合并singleCloset并提交结果:所以您最终调用: entityManager.merge(singleCloset); entityManager.getTransaction()。commit();