让我们说我有三堂课。
public class Parent {
@Id
@GeneratedValue
@Column(name = "parent_id", updatable = false, insertable = false)
private Long id;
private String name;
@Builder.Default
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
Set<Child> childs = new HashSet<>();
}
public class Child {
@Id
@GeneratedValue
@Column(name = "child_id", updatable = false, insertable = false)
private Long id;
private String name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name ="parent_id")
Parent parent;
@Builder.Default
@OneToMany(mappedBy = "child", cascade = CascadeType.ALL)
Set<GrandChild> grandChildren = new HashSet<>();
}
public class GrandChild {
@Id
@GeneratedValue
@Column(name = "grandchildid", updatable = false, insertable = false)
private Long id;
private String name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "child_id")
Child child;
}
如果我随后通过GrandChild grandChild
创建新的parent.getChilds().get(0).getGranChilds().add(grandChild)
并通过parentRepo.save(parent)
保存实体。局部变量grandChild
将没有id
。但是,如果我先刷新然后保存,则本地变量将具有ID?这是您通常会做的事情吗?
我想这会在您保存然后刷新时发生。但是似乎只有在我先冲洗然后保存时才能工作。
添加grandChild:
GrandChild grandChild = GrandChild.builder().name(name).build();
Parent parent = parentRepo.findAll().get(0);
Optional<Child> optional = parent.getChilds().stream().findAny();
optional.ifPresent(child -> child.getGrandChildren().add(grandChild));
(这只是示例代码,所以不要介意丑陋)。
保存后刷新(未为本地变量生成ID,仍然保存实体):
parentRepo.saveAndFlush(parent);
System.out.println(grindChild.getId()); // null
先冲洗(局部变量获取ID)
parentRepo.flush();
parentRepo.save(parent);
System.out.println(grandChild.getId()); //not null, value exists
在两种情况下,该ID都是在数据库中生成的。
答案 0 :(得分:0)
我假设您可以保存实例而无需刷新并将结果分配给局部变量。请从CrudRepository
界面中查看以下javadoc注释:
/**
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity must not be {@literal null}.
* @return the saved entity will never be {@literal null}.
*/
<S extends T> S save(S entity);
我认为您可以尝试以下方法:
Parent persistentParent = parentRepo.saveAndFlush(parent);
persistentParent
应具有可用的生成的ID值。
UPD
在与数据库同步时生成ID。因此,只有在刷新会话后才能使用。
答案 1 :(得分:0)
这里的问题是,根据保存之前或之后是否进行刷新来执行不同的级联操作。
如果在保存之前刷新,则实体将通过ACTION_PERSIST_ON_FLUSH
级联保存,该级联使用与本地变量相同的对象引用。
如果我在保存后刷新,则实体将通过ACTION_MERGE
级联保存,该级联会在生成ID之前在实体上进行复制,因此引用不同,这意味着局部变量将没有ID 。
在这两种情况下,saveWithGeneratedId(...)
类都被调用org.hibernate.event.internal.AbstractSaveEventListener
。只是具有不同的对象引用。