【问题标题】:JPA + JSON deserializationJPA + JSON 反序列化
【发布时间】:2016-02-16 01:38:18
【问题描述】:

我对 JPA 很陌生,并且使用 Java 作为 REST 服务的后端,我想将 JSON 存储到数据库中,并想检查什么是最好的方法。请让我知道,以防我走“长路”。

(我正在使用 Spring)

我的数据:

{
  frequency: "Week"
  isGoalOrMore: "true"
  name: "Develop"
  targetValue: "5"
  type: "Average"
}

习惯.java

@Entity
@Table(name = "habits")
public class Habit {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "id_habit_type")
    private HabitType type;

    private boolean isGoalOrMore; //basically means, achieve goal or do more
    private double targetValue;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "id_frequency")
    private Frequency frequency;

    //getters and setters
}

HabitType.java

 @Entity
 @Table(name = "habits_type")
 public class HabitType {

     @Id
     private Long id;

     private String description;

 }

数据库模型(mysql)

habits
  --id
  --name
  --id_frequency
  --id_habit_type

habits_type
  --id
  --description

问题

当我尝试保存这些数据时,我收到如下错误:

com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class com.tiperapp.model.HabitType] from String value ('Average'); no single-String constructor/factory method

我该如何解决?

通过阅读一些主题,一种选择是编写 JSON 反序列化器。他们通过修复 JPA 解决了其他情况。 我想知道哪个会被推荐..你们能帮我如何反序列化这个,最好的方法吗?

【问题讨论】:

    标签: json spring jpa


    【解决方案1】:

    恕我直言,最好的解决方案是将您发送到浏览器或从浏览器接收的数据(我将其称为 DTO)和您存储在数据库中的数据视为两个不同的东西。

    当然,它们通常看起来一样。但它们是不同的。两者不能完全相同。例如:

    • 实体构成一个巨大的图,通常包含双向关联,并且没有限制,因为所有内容都可以延迟加载。例如,订单行有订单,有买家,有地址,有城市,有国家,有......订单行,否则您会将数据库的一半序列化为 JSON。
    • JSON 有时对同一事物的表示形式与数据库不同。例如,您将数据库中的所有习惯类型存储为带有 ID 和描述的行,但 JSON 似乎只真正关心描述。 ID 似乎是一种避免在各处重复相同描述的方法。
    • 最终用户无法看到实体的许多属性(出于安全原因),或者仅与某些用例相关,等等。

    因此我会为两者使用不同的类。当你收到一个 JSON 格式的 HabitDTO 时,你用 Jackson 将它反序列化为一个 HabitDTO 实例,然后在 DTO 中找到与描述对应的 HabitType 实体,并根据 HabitDTO 中的相应信息创建/更新 Habit 实体实例。

    回顾一下:实体包含应用程序的完整业务模型,用于实现所有功能用例。 DTO 包含序列化信息,用于向/从客户端传输一小部分信息,通常用于特定用例。明确区分两者可以带来更大的灵活性:您可以在不更改服务接口的情况下更改底层持久性模型,反之亦然。

    【讨论】:

    • 天哪!非常感谢你把这一切放在一起!这很有意义,我没有想到您所说的这些事情,例如有时您可能只想发送一部分数据。我会照你说的做的! :)
    • 请给我建议哪种方式(反)序列化更好:手动读取和写入 json 数据到 DTO,或使用杰克逊注释?
    • 在 DTO 上使用 Jackson 注释。
    【解决方案2】:

    你的 json 错误。

    type 不是映射到字符串而是映射到对象。你可以通过使用这个来做到这一点:

    {
      frequency: "Week"
      isGoalOrMore: "true"
      name: "Develop"
      targetValue: "5"
      type: {
        description: "A DESCRIPTION"
        id: "Average"
      }
    }
    

    【讨论】:

    • 嗨 Tahar,我想只发送一个字符串 Average,它会匹配我的表。这个表基本上是一个域表,所以它可以避免错误,以防我发送其他像Averge 这样不可接受的值。我想休眠到我的数据库并检查'哦,你发送了Average,它的ID是2。这甚至可能吗?大声笑:)
    • 可以做到的,请参阅@JB Nizet 关于 dto 使用的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多