使用 Hibernate 和 JPA 持久化 JSON 对象

新手上路,请多包涵

我正在尝试在 Spring Boot 中将 JSON 对象存储在 MySQL 数据库中。我知道我做错了什么,但我无法弄清楚那是什么,因为我对 Spring 还很陌生。

我有一个休息端点,我在其中获取以下 JSON 对象(通过 HTTP PUT),我需要将其存储在数据库中,以便用户稍后可以获取它(通过 HTTP GET)。

 {
  "A": {
    "Name": "Cat",
    "Age": "1"
  },
  "B": {
    "Name": "Dog",
    "Age": "2"
  },
  "C": {
    "Name": "Horse",
    "Age": "1"
  }
}

请注意,在上述情况下,对象 中的 可能会有所不同,由于该要求,我使用 HashMap 来捕获控制器中的对象。

 @RequestMapping(method = RequestMethod.POST)
    public String addPostCollection(@RequestBody HashMap<String, Animal> hp) {

        hp.forEach((x, y) -> {
            postRepository.save(hp.get(x));
        });

        return "OK";

    }

正如您在该方法中看到的,我可以迭代 HashMap 并将每个 Animal 对象保留在数据库中。但我正在寻找一种方法将整个 HashMap 在一条记录中。我读了一些书,他们建议我使用 @ManyToMany 映射。

谁能指出我以不同方式坚持 HashMap 的方向? (或者正在使用 @ManyToMany 唯一正确的方法?)

原文由 Fawzan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 664
2 个回答

Maven 依赖

您需要做的第一件事是在您的项目中设置以下 Hibernate Types Maven 依赖 pom.xml 配置文件:

 <dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

领域模型

假设您有以下实体:

 @Entity(name = "Book")
@Table(name = "book")
@TypeDef(
    typeClass = JsonType.class,
    defaultForType = JsonNode.class
)
public class Book {

    @Id
    @GeneratedValue
    private Long id;

    @NaturalId
    private String isbn;

    @Column(columnDefinition = "jsonb")
    private JsonNode properties;

    //Getters and setters omitted for brevity
}

注意 @TypeDef 用于指示 Hibernate 使用 Hibernate Types 项目提供的 JsonType 映射 JsonNode 对象。

测试时间

现在,如果你保存一个实体:

 Book book = new Book();
book.setIsbn( "978-9730228236" );
book.setProperties(
    JacksonUtil.toJsonNode(
        "{" +
        "   \"title\": \"High-Performance Java Persistence\"," +
        "   \"author\": \"Vlad Mihalcea\"," +
        "   \"publisher\": \"Amazon\"," +
        "   \"price\": 44.99" +
        "}"
    )
);

entityManager.persist( book );

Hibernate 将生成以下 SQL 语句:

 INSERT INTO
    book
(
    isbn,
    properties,
    id
)
VALUES
(
    '978-9730228236',
    '{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99}',
    1
)

你也可以加载它并修改它:

 Session session = entityManager.unwrap( Session.class );

Book book = session
    .bySimpleNaturalId( Book.class )
    .load( "978-9730228236" );

LOGGER.info( "Book details: {}", book.getProperties() );

book.setProperties(
    JacksonUtil.toJsonNode(
        "{" +
        "   \"title\": \"High-Performance Java Persistence\"," +
        "   \"author\": \"Vlad Mihalcea\"," +
        "   \"publisher\": \"Amazon\"," +
        "   \"price\": 44.99," +
        "   \"url\": \"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/\"" +
        "}"
    )
);

Hibernate 为您处理 UPDATE 声明:

 SELECT  b.id AS id1_0_
FROM    book b
WHERE   b.isbn = '978-9730228236'

SELECT  b.id AS id1_0_0_ ,
        b.isbn AS isbn2_0_0_ ,
        b.properties AS properti3_0_0_
FROM    book b
WHERE   b.id = 1

-- Book details: {"price":44.99,"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon"}

UPDATE
    book
SET
    properties = '{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99,"url":"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/"}'
WHERE
    id = 1

原文由 Vlad Mihalcea 发布,翻译遵循 CC BY-SA 4.0 许可协议

您的 JSON 结构良好,因此通常无需将整个地图保存在一条记录中。您将无法使用 Hibernate/JPA 查询功能以及更多功能。

如果你真的想将整个地图保存在一条记录中,你可以将地图保存在它的字符串表示中,并且正如已经提议的那样,使用像 Jackson 这样的 JSON 解析器来重建你的 HashMap

 @Entity
public class Animals {

  private String animalsString;

  public void setAnimalsString(String val) {
    this.animalsString = val;
  }

  public String getAnimalsString() {
    return this.animalsMap;
  }

  public HashMap<String, Animal> getAnimalsMap() {
    ObjectMapper mapper = new ObjectMapper();
    TypeReference<HashMap<String,Animal>> typeRef = new TypeReference<HashMap<String,Animal>>() {};
    return mapper.readValue(animalsString, typeRef);
  }

}

你的动物类别:

 public class Animal {

  private String name;
  private int age;

  /* getter and setter */
  /* ... */
}

您可以将控制器方法更改为

@RequestMapping(method = RequestMethod.POST)
public String addPostCollection(@RequestBody String hp) {
  Animals animals = new Animals();
  animals.setAnimalsString(hp);
  animalsRepository.save(hp);
  return "OK";
}

原文由 kaaas 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题