java - JPA 通过刷新嵌套实体策略持久化实体

标签 java hibernate jpa

我问自己如何才能执行以下场景:

让我们看一个示例实体 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.PERSISTCascade.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"
        }
    ]
}

为了避免样板,想象 DtoDtoToEntityMapper (和反向)存在并按预期工作。

问题是我什么时候会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 的最佳方式是什么?字段?

  1. 我应该使用 refresh(item)之后persist(item)
  2. 我应该使用附加 Category而不是分离,从而获取每个 Category使用id之前persist(item)
  3. 我可以对请求(POST请求正文)和响应使用相同的表示形式,因此名称将被预先填充。但是如果 id 会发生什么?是正确的,但是 name不是(因为我不接受 Category 来自 Item 的更新)?直接忽略name或引发异常?
  4. 其他方式

此外,如果 2. 是最佳解决方案,我应该在哪里获取这些嵌套实体?我的意思是在 Controller (表示层),位于 DtoToEntityMapper (表示层),位于 Service (服务层)

<小时/>

PS:请我坚持JPA规范而不使用 Hibernate具体功能。 PS2:我可以做单POST请求

最佳答案

使用 entityManager.merge() 而不是 entityManager.persist() 应该可以解决问题。它将返回托管实例,因此访问其类别应该会为您提供包括描述的类别。

注意:请确保在调用后使用托管实例。

关于java - JPA 通过刷新嵌套实体策略持久化实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46532603/

相关文章:

java - 组件重复 onResume

java - 可执行 JAR 执行不同于 eclipse 执行

java - 用于生产的外部容器中的 Spring Boot 嵌入式容器或 war 文件

Hibernate 配置类的 java.lang.NoSuchMethodError 仅出现在 Tomcat 上

MySQL Workbench 模型到 Java 持久性实体

java - 用单引号替换方法时 Hibernate session.createQuery 错误

java - JPA Long @Id as JAXB @XmlID 生成 XSD 验证错误

java - 在没有在 ContentValues 中设置所有列的情况下更新数据库中的项目

java - 如何使用 JPA 和 LIKE "%value%"搜索 Google AppEngine 数据存储?

java - 使用 @ManyToMany 关联连接三个表