我问自己如何才能执行以下场景:
让我们看一个示例实体 Item
@Data
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Entity
class Item implements Serializable {
@Id
@GeneratedValue
@Setter(AccessLevel.NONE)
private UUID id;
private String name;
@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH})
@JoinTable(name = "item_category", joinColumns = {@JoinColumn(name = "item_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "category_id", referencedColumnName = "id")})
private Set<Category> categories;
@PrePersist
protected void generateUuid() {
id = UUID_GENERATOR.generate();
}
}
和Category
@Data
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Entity
class Category implements Serializable {
@Id
@GeneratedValue
@Setter(AccessLevel.NONE)
private UUID id;
private String name;
@PrePersist
protected void generateUuid() {
id = UUID_GENERATOR.generate();
}
}
在我的用例中,Item
应该有很多Category
但是Item
无法直接创建或更新Category
,它必须使用现有的Category
(图像是管理员管理的类别的下拉列表)。这就是为什么Cascade.PERSIST
和Cascade.MERGE
失踪了。
现在想象一下以下 API POST /api/items
具有这样的JSON请求结构
{
"name": "new item",
"categories": [
"6d126e36-a7a5-11e7-abc4-cec278b6b50a",
"88d5a052-a7a5-11e7-abc4-cec278b6b50a"
]
}
这应该使用现有的 Category
创建一个新项目给定的 ids(认为 ids 是正确且存在的)。
但是我会返回包含完整嵌套实体值的响应:
{
"name": "new item",
"categories": [
{
"id": "6d126e36-a7a5-11e7-abc4-cec278b6b50a",
"name": "CAT_A"
},
{
"id": "88d5a052-a7a5-11e7-abc4-cec278b6b50a",
"name": "CAT_B"
}
]
}
为了避免样板,想象 Dto
和DtoToEntityMapper
(和反向)存在并按预期工作。
问题是我什么时候会persist()
新Item
实体从 JSON 生成:
Item(
id=null,
name="new item",
Categories:[
Category(
id="6d126e36-a7a5-11e7-abc4-cec278b6b50a",
name=null
),
Category(
id="6d126e36-a7a5-11e7-abc4-cec278b6b50a",
name=null
)
]
)
下面的每个实例都是分离的。
问题出现在persist()
之后每Category
实例似乎已分离(或者至少 name
仍然等于 null
)。
那么检索 Category
的最佳方式是什么?字段?
- 我应该使用
refresh(item)
之后persist(item)
? - 我应该使用附加
Category
而不是分离,从而获取每个Category
使用id
之前persist(item)
? - 我可以对请求(
POST
请求正文)和响应使用相同的表示形式,因此名称将被预先填充。但是如果id
会发生什么?是正确的,但是name
不是(因为我不接受Category
来自Item
的更新)?直接忽略name
或引发异常? - 其他方式
此外,如果 2. 是最佳解决方案,我应该在哪里获取这些嵌套实体?我的意思是在 Controller
(表示层),位于 DtoToEntityMapper
(表示层),位于 Service
(服务层)
PS:请我坚持JPA
规范而不使用 Hibernate
具体功能。
PS2:我可以做单POST
请求
最佳答案
使用 entityManager.merge()
而不是 entityManager.persist()
应该可以解决问题。它将返回托管实例,因此访问其类别应该会为您提供包括描述的类别。
注意:请确保在调用后使用托管实例。
关于java - JPA 通过刷新嵌套实体策略持久化实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46532603/