我有一个一对多的关系,如下所示-
@Entity
@Table(name = "PARENT_TABLE")
public class Parent {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "PARENT_ID", updatable = false, nullable = false, length = 16)
@Type(type="uuid-binary")
private UUID id;
private String parentName;
@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="PARENT_ID")
@Cascade(CascadeType.ALL)
private List<Child> children;
}
@Entity
@Table(name = "CHILD_TABLE")
public class Child {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "CHILD_ID", updatable = false, nullable = false, length = 16)
@Type(type="uuid-binary")
private UUID id;
private String childName;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID")
private Parent parent;
}
现在,我已经有一个有2个孩子的父母,我有一个对parent的更新调用,它正在更新父母中的一些信息并在父母中添加一个孩子。
List<Child> existingChild = getFromDbByParent(parent);
existingChild.add(new Child());
hibernateTemplate.update(parent);
上面的代码失败了,因为对于第三个孩子,休眠时保存到数据库时不会创建ID。所以,我得到了错误
2019-12-19 13:02:04.589 DEBUG SqlExceptionHelper io-12347-exec-1 could not execute batch [update CHILD_TABLE set CHILD_ID =null where PARENT_ID=?]
java.sql.BatchUpdateException: ORA-01407: cannot update ("DB"."CHILD_TABLE"."CHILD_ID") to NULL
即使使用JPA Cascade批注,创建父级和新子级也可以正常工作。在这里可以做什么?
注意:这是向休眠项目迁移的回购层,所以我试图避免更改逻辑,这就是为什么要在现有父级中保存新子级。我知道,最好先给孩子省钱。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
在Hibernate中,当你在一个已存在的Parent对象上直接添加一个新的Child对象到其集合中,并尝试更新Parent时,Hibernate默认不会自动为新加入的Child分配ID。你需要显式地初始化或保存这个新的Child实体,以确保它在被关联到Parent之前拥有一个合法的ID。
这里有一种修改方法,可以在不改变太多逻辑的情况下解决问题:
// 获取现有的孩子列表
List<Child> existingChildren = getFromDbByParent(parent);
// 创建新的Child实例并初始化(确保ID生成)
Child newChild = new Child();
// 注意:对于UUID类型的ID,Hibernate通常会在对象被持久化时自动生成,
// 但如果你使用了特定的生成策略(如你代码中的uuid2),确保该策略能在此处生效。
// 如果需要,可以检查你的配置以确认UUID生成时机。
// 将新孩子添加到现有孩子列表
existingChildren.add(newChild);
// 保存新的Child实体,确保它在数据库中有一个ID
hibernateTemplate.save(newChild); // 这行是关键
// 更新Parent,此时新Child已经具有ID
parent.setChildren(existingChildren);
hibernateTemplate.update(parent);
通过先调用hibernateTemplate.save(newChild)
来保存新创建的Child实体,你可以确保在将其添加到Parent的集合中并更新Parent时,Child已经有了一个非空的ID。这样就可以避免在执行批量更新时遇到试图将CHILD_ID
设置为NULL的问题。