geo*_*ydv 3 java hibernate jpa spring-data-jpa
我正在尝试使用JPA(使用Hibernate)来保存2个实体.Spring数据提供了界面,但我认为这并不重要.
我有一个名为'Model'的主要实体.此模型链接了许多"参数"实体.我正在编写一种方法来保存模型及其参数.
这是方法:
private void cascadeSave(Model model) {
modelRepository.save(model);
for (ParameterValue value : model.getParameterValues()) {
parameterValueRepository.save(value);
}
}
Run Code Online (Sandbox Code Playgroud)
这就是问题:
当我加载之前已经存在的模型时,向它添加一些新参数然后调用此方法来保存它们发生的奇怪事情:
在第一次保存(modelRepository.save)之前,这是调试时模型的数据:
该模型有2个参数,填充值(名称和模型已填充).
现在,在保存模型后,我的方法中的第一个保存就会发生这种情况.请注意,对象引用是一个不同的对象引用,所以Hibernate必须做一些神奇的事情并重新创建值而不是让它们孤立:
出于某种原因,hibernate清除了集合中参数的所有属性.
现在,当在以下代码中保存新参数时,由于非空约束等原因而失败.
我的问题:为什么hibernate会清除所有字段?
以下是相关映射:
的parameterValue
@Entity
@Table(name = "tbl_parameter_value")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "PARAMETER_TYPE")
public abstract class ParameterValue extends AbstractBaseObject {
@Column(nullable = false)
@NotBlank
private String name;
private String stringValue;
private Double doubleValue;
private Integer intValue;
private Boolean booleanValue;
@Enumerated(EnumType.STRING)
private ModelType modelParameterType;
@Column(precision = 7, scale = 6)
private BigDecimal bigDecimalValue;
@Lob
private byte[] blobValue;
ParameterValue() {
}
ParameterValue(String name) {
this.name = name;
}
Run Code Online (Sandbox Code Playgroud)
ModelParameterValue
@Entity
@DiscriminatorValue(value = "MODEL")
public class ModelParameterValue extends ParameterValue {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "model_id", foreignKey = @ForeignKey(name = "FK_VALUE_MODEL"))
private Model model;
ModelParameterValue() {
super();
}
ModelParameterValue(String name) {
super(name);
}
Run Code Online (Sandbox Code Playgroud)
模型
@Entity
@Table(name = "tbl_model")
public class Model extends AbstractBaseObject implements Auditable {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "model")
private Set<ModelParameterValue> parameterValues = new HashSet<>();
Run Code Online (Sandbox Code Playgroud)
编辑
我能用最小的例子重现这一点.如果你更换所有弹簧数据,这就是幕后发生的事情(em是JPA EntityManager):
public Model simpleTest() {
Model model = new Model("My Test Model");
em.persist(model);
model.addParameter(new Parameter("Param 1"));
em.merge(model);
for (Parameter child : model.getParameters()) {
em.persist(child);
}
return model;
}
Run Code Online (Sandbox Code Playgroud)
执行合并时,参数的所有属性都设置为null.它们实际上只是被全新的参数所取代.
我猜你使用的是Spring Data Jpa作为你的modelRepository.这表明了以下后果.
S保存(S实体)
保存给定的实体.使用返回的实例进行进一步操作,因为save操作可能已完全更改了实体实例.
所以这是你遇到的正常行为.
代码应更改为:
model = modelRepository.save(model);
for (ParameterValue value : model.getParameterValues()) {
parameterValueRepository.save(value);
}
Run Code Online (Sandbox Code Playgroud)
编辑:
我认为你的保存功能在意义上是破坏的,你是向后做的.你可以在你的关系中使用CascadeType,或者你必须先保存孩子.
Cascade的工作方式类似于"如果您保存父级,保存子级,如果您更新父级,则更新子级......"
所以我们可以像你那样对你的关系进行级联:
@Entity
@Table(name = "tbl_model")
public class Model extends AbstractBaseObject implements Auditable {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "model", cascade = CascadeType.ALL)
private Set<ModelParameterValue> parameterValues = new HashSet<>();
Run Code Online (Sandbox Code Playgroud)
然后才这样保存
private void cascadeSave(Model model) {
modelRepository.save(model);
//ParamValues will be saved/updated automaticlly if your model has changed
}
Run Code Online (Sandbox Code Playgroud)
第二种选择只是首先保存params然后用它们建模.
private void cascadeSave(Model model) {
model.setParameterValues(
model.getParameterValues().stream()
.map(param -> parameterValueRepository.save(param))
.collect(Collectors.toSet())
);
modelRepository.save(model);
}
Run Code Online (Sandbox Code Playgroud)
我没有检查我的编译器中的第二个代码,但想法是首先保存子项(ParamValues),将其放入模型然后保存模型:)
| 归档时间: |
|
| 查看次数: |
94 次 |
| 最近记录: |