【问题标题】:@OneToMany Relationship in JPA doesn't work properlyJPA 中的@OneToMany 关系无法正常工作
【发布时间】:2019-08-15 14:17:05
【问题描述】:

您好,我有以下关系:

@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 的 Athlete,然后找到 Id=5 的壁橱。但随后它完全忽略了将运动员添加到等待列表中的其余代码,并且不会将其持久化到数据库中。

现在显示真正的问题是为什么会发生这种情况?

解决方案:

除了@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 对象吗?

【问题讨论】:

  • 您可能没有在事务中运行该代码,或者忘记提交事务。您发布的代码可以改进,但它是正确的。
  • 豆类?您是在使用 EJB 事务还是如何持久化壁橱?从哪里调用方法?
  • @PeterŠály 我正在从无状态 LocalBean EJB Bean 调用方法 addAthleteIntoWaitingList。
  • 你已经在调用 merge(closet) 了吗?

标签: jpa jakarta-ee entity


【解决方案1】:

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

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

显式调用 entityManager.merge(closet)。

【讨论】:

  • 嘿,谢谢你的建议,但这对我不起作用。在我添加对象 singleAthlete 时,它​​已经存在。所以这种级联类型会带来一个主键被违反的异常,因为 JPA 会尝试将这个对象插入更多。
  • 使用上述级联显式调用 entityManager.merge(closet)
  • 嘿,彼得,它确实奏效了。非常感谢。虽然我仍然不明白 JPA 上下文发生了什么。我认为在保存它的属性中所做的每一个更改都不需要显式调用任何更新或合并方法,不是吗?
  • 在此处查看有关实体生命周期的更多信息dzone.com/articles/jpa-entity-lifecycle
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-26
    • 2014-12-21
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多