单向@OneToMany 不能按预期使用@EmbeddedId
Unidirectional @OneToMany does not work as expected with @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<>();
...
}
并且当执行此对象的创建并添加子评论时,当保存到数据库时,一切都按预期工作(子 PostCommentUniMany
上的 ID 按预期添加)但更改不会传播到 java代码(图片中的对象 @12081
应该将 id
字段更新为 2
而不是 null
)。
在其他情况下(案例 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 中一样)。
如何更新案例 1 中的对象 @12081
以反映 DB id?
更新
经过下面的讨论 - 问题是如果手动将实体上的 id
设置为某个值,Spring 认为它不是新实体并尝试合并而不是保留实体。
"workarounds" 之一是在 @Entity
class PostOneUni
上设置 @Version
字段,它将跟踪实体是否是新的。
@Version
private Integer version;
问题是因为您手动设置了 ID 字段 Spring 数据调用合并操作而不是持久化:
见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 Merging Detached Entity State
• If X is a new entity instance, a new managed entity instance X' is
created and the state of X is copied into the new managed entity
instance X'.
在你的测试代码中,如果你这样做:
post = oneToManyService.addNewPost(post);
标识符在返回的实例上正确设置,就像从数据库重新加载时一样。但是,原始实例(处于 'new' 状态)保持不变,即没有设置 ID。
在调用 persist 而不是 merge 的情况下,将返回原始(相同)实例,并将在此实例上正确设置标识符。
如果我使用这段代码(图中的案例 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<>();
...
}
并且当执行此对象的创建并添加子评论时,当保存到数据库时,一切都按预期工作(子 PostCommentUniMany
上的 ID 按预期添加)但更改不会传播到 java代码(图片中的对象 @12081
应该将 id
字段更新为 2
而不是 null
)。
在其他情况下(案例 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 中一样)。
如何更新案例 1 中的对象 @12081
以反映 DB id?
更新
经过下面的讨论 - 问题是如果手动将实体上的 id
设置为某个值,Spring 认为它不是新实体并尝试合并而不是保留实体。
"workarounds" 之一是在 @Entity
class PostOneUni
上设置 @Version
字段,它将跟踪实体是否是新的。
@Version
private Integer version;
问题是因为您手动设置了 ID 字段 Spring 数据调用合并操作而不是持久化:
见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 Merging Detached Entity State
• If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.
在你的测试代码中,如果你这样做:
post = oneToManyService.addNewPost(post);
标识符在返回的实例上正确设置,就像从数据库重新加载时一样。但是,原始实例(处于 'new' 状态)保持不变,即没有设置 ID。
在调用 persist 而不是 merge 的情况下,将返回原始(相同)实例,并将在此实例上正确设置标识符。