gpt4 book ai didi

java - EntityManager.merge() 不保留相关实体

转载 作者:行者123 更新时间:2023-11-30 09:07:47 24 4
gpt4 key购买 nike

我正在使用 eclipselink 进行基本的 JPA 设置。我有一个管理元素库存量的实体。我想跟踪这些元素的库存历史记录,因此我希望每次更新数量时也创建一个新的历史记录条目。

问题是,当我在 @PreUpdate 方法中将新的历史实体添加到历史列表时,它不会与 Wine 实体保持一致。在调用 merge() 之前或在 @PrePersist 方法中手动添加 History 实体会按预期工作。

以下是我的代码:

Wine.java

@Entity
public class Wine implements Serializable {

@Id
@GeneratedValue
private long id;

@Transient
private int oldAmount;

@Column
private int amount;

@OneToMany(mappedBy = "wine", cascade = CascadeType.ALL)
private List<AmountHistory> history;

//getters & setters

@PostLoad
@PostUpdate
@PostPersist
private void onLoad() {

oldAmount = amount;
}

@PrePersist
private void onPersist() {

final History history = new History();
history.setOldAmount(0);
history.setNewAmount(amount);
history.setWine(this);

this.history = new ArrayList<>();

this.history.add(history);
}

@PreUpdate
private void onUpdate() {

if (oldAmount != amount) {
final History history = new History();
history.setOldAmount(oldAmount);
history.setNewAmount(amount);
history.setWine(this);

this.history.add(history);
}
}
}

历史.java

@Entity
public class History implements Serializable {

@Id
@GeneratedValue
private long id;

@Column
private int oldAmount;

@Column
private int newAmount;

@ManyToOne(cascade = CascadeType.ALL)
private Wine wine;

//getters & setters
}

我目前有一个解决方法,即在 setter 方法中添加金额的历史记录条目,但我不相信这个解决方案,因为当 merge() 未被调用时,它也会创建历史记录实体。

我需要做什么来解决这个问题?或者有人可以解释为什么会这样吗?

最佳答案

来自 JPA 规范的第 3.5 节:“一般来说,可移植应用程序的生命周期方法不应该调用 EntityManager或查询操作、访问其他实体实例或修改内部关系相同的持久性上下文。 [43]生命周期回调方法可以修改非关系调用它的实体的状态。”

因此您不应尝试在 preUpdate 回调中修改您的关系。在这种情况下,它不会像您预期的那样工作,因为 preUpdate 发生在合并已经发生并级联关系之后 - JPA 不提供无需手动调用即可再次触发合并的方法。

解决方案是使用您的访问器方法来跟踪更改,就像您已经在做的那样。除了跟踪 oldAmount,还添加一个新的历史实例。这样您的合并将获得关系以及更改的数量。

关于java - EntityManager.merge() 不保留相关实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23850872/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com