java - 单向 @OneToMany 不能按预期使用 @EmbeddedId
问题描述
如果我使用这段代码(图片中的案例 1):
@Data
@Entity
public class PostOneUni {
@EmbeddedId //if @Id, class CompositeId must be annotated @Embeddable?
private CompositeId id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumns({
@JoinColumn(name = "id1"),
@JoinColumn(name = "id2")
})
private Set<PostCommentUniMany> comments = new HashSet<>();
...
}
并且当执行创建此对象并添加子注释时,当保存到 DB 时,一切都按预期工作(子PostCommentUniMany
上的 id 按预期添加)但更改不会传播到 java 代码(@12081
图片中的对象应该将id
字段更新为2
而不是null
)。
在其他情况下(CASE 2)我使用这个代码:
@Data
@Entity
public class PostOneUni {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "post_id")
private Set<PostCommentUniMany> comments = new HashSet<>();
...
}
从图片中可以看出,字段也被持久化到 DB,并且用于将状态保存到 DB 的对象在保存后被更新(对象@12052
被更新以反映id
字段是2
- 就像在 DB 中一样)。
如何更新@12081
案例 1 中的对象以反映数据库 ID?
更新
经过下面的讨论 - 问题是如果id
实体被手动设置为某个值,Spring 认为它不是新实体并尝试进行合并而不是持久化实体。
“解决方法”之一是在类上设置@Version
字段,以跟踪实体是否是新的。@Entity
PostOneUni
@Version
private Integer version;
解决方案
问题是因为您手动设置了 ID 字段,所以 Spring Data 调用合并操作而不是持久化:
见 org.springframework.data.jpa.repository.support.SimpleJpaRepository
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) //checks if ID null {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
JPA 规范指出,当
3.2.7.1 合并分离实体状态
• 如果X 是一个新的实体实例,则创建一个新的受管实体实例X',并将X 的状态复制到新的受管实体实例X' 中。
在您的测试代码中,如果您这样做:
post = oneToManyService.addNewPost(post);
标识符在返回的实例上正确设置,就像从数据库重新加载时一样。但是,原始实例(处于“新”状态)保持不变,即没有设置 ID。
在调用persist而不是合并的地方,则返回原始(相同)实例,并且将在此实例上正确设置标识符。
推荐阅读
- c++ - 如何在 C++ 中向下转换以从父实例调用子函数?
- r - 如何使用“persp”函数在 R 中绘制不连续的曲面
- javascript - 如何在 VueJs 中使用 IdleVue 组件配置 IdleTime?
- clojurescript - 即使 :component-did-update 被调用,form-3 组件也不会重新渲染任何内容
- r - R, hclust : 如何为每个集群创建一个代表?
- html - 在 Bootstrap 列中动态调整圆形 div 的大小
- django - css 文件在 django 中正确加载,但在网页上看不到样式
- javascript - 使用 React 获取文件路径
- java - 如何在用户仍在输入 java 时读取输入?
- telerik - grid.setOptions(JSON.parse(options)); 使数据源为空