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

@OneToMany Relationship in JPA doesn't work properly

你好我有以下关系:

@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 中 class 我有这个代码:

  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 后,table 运动员中的 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 的 Athlete,然后找到 Id=5 的壁橱。但是随后它完全忽略了将 Athlete 添加到 waitingList 中的其余代码,并且不会将其保存到数据库中。

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

解决方案:

除了@Peter 的完美解决方案外,我做了以下更改,没有添加任何级联类型,更重要的是没有调用合并方法:

我改变了我的方法获取对象 Athlete 的方式。我没有将它作为参数提供,而是通过我的 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 对象?

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

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

显式调用 entityManager.merge(壁橱)。

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