8

我有具有列“首选项”的数据类/表“用户”

CREATE table "user"; 
ALTER TABLE "user" ADD COLUMN preferences TEXT;

首选项类型是 TEXT,我在那里存储 JSON。

public class User extends AbstractEntity{
public String preferences;
}

所以user.preferences价值是"{notifyByEmail:1, favouriteColor:"blue" }"

我怎样才能用一些注释来包装它,这样我就可以像访问它一样

user.preferences.notifyByEmail

或无需包装成数据对象

user.preferences.get("notifByEmail");
user.preferences.set("notifByEmail",true);

我想可能有一些杰克逊注释可以添加到字段中,例如

@JsonGenerate
public String preferences;

我对 JPA 还很陌生,文档也很丰富。

我相信我的情况很常见。谁能举个例子?

4

4 回答 4

14

可以使用 JPA Converter 实现这一点。

实体;

@Id
@GeneratedValue
Long id;

@Column(name = "mapvalue")
@Convert(converter = MapToStringConverter.class)
Map<String, String> mapValue;

转换器:

@Converter
public class MapToStringConverter implements AttributeConverter<Map<String, String>, String> {

    ObjectMapper mapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(Map<String, String> data) {
        String value = "";
        try {
            value = mapper.writeValueAsString(data);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return value;
    }

    @Override
    public Map<String, String> convertToEntityAttribute(String data) {
        Map<String, String> mapValue = new HashMap<String, String>();
        TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
        };
        try {
            mapValue = mapper.readValue(data, typeRef);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mapValue;
    }

}

保存数据:

Map<String, String> mapValue = new HashMap<String, String>();
mapValue.put("1", "one");
mapValue.put("2", "two");
DataEntity entity = new DataEntity();
entity.setMapValue(mapValue);
repo.save(entity);

该值将存储在数据库中

{"1":"three","2":"two"}
于 2017-01-05T08:39:11.173 回答
5

老实说,我认为您最好的解决方案是为您的属性创建一个单独的表(首选项)。

+------------+
| preference |
+------------+---------+------+-----+
| Field      | Type    | Null | Key |
+------------+---------+------+-----+
| user_id    | bigint  | NO   | PRI |
| key        | varchar | NO   | PRI |
| value      | varchar | NO   |     |
+------------+---------+------+-----+

您可以像这样将其映射到您的实体中:

@Entity
public class User
{
    @Id
    private Long id;

    @ElementCollection
    @MapKeyColumn(name = "key")
    @Column(name = "value")
    @CollectionTable(name = "preference",
        joinColumns = @JoinColumn(name = "user_id"))
    private Map<String, String> preferences;
}

通过这种方式,您的数据库更加规范化,您不必胡乱使用“创造性解决方案”,例如将首选项存储为 JSON。

于 2012-08-15T13:14:27.433 回答
4

使用 Hibernate 持久化 JSON 对象非常容易。

您不必手动创建所有这些类型,只需使用以下依赖项通过 Maven Central 获取它们:

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

有关更多信息,请查看Hibernate Types 开源项目

现在,您需要@TypeDef在类级别或package-info.java包级别描述符中添加此注释以使用JsonTypeHibernate 类型:

@TypeDef(
    name = "json",
    typeClass = JsonType.class
)

实体映射将如下所示:

@Type(type = "json")
@Column(columnDefinition = "jsonb")
private String preferences;

就是这样!

于 2017-11-01T11:29:29.023 回答
2

如果您真的需要类似的东西,最推荐的是执行以下操作:

public class User extends AbstractEntity{
  @JsonIgnore //This variable is going to be ignored whenever you send data to a client(ie. web browser)
  private String preferences;

  @Transient //This property is going to be ignored whenever you send data to the database
  @JsonProperty("preferences") //Whenever this property is serialized to the client, it is going to be named "perferences" instead "preferencesObj"
  private Preferences preferencesObj;

  public String getPreferences() {
    return new ObjectMapper().writeValueAsString(preferencesObj);
  }

  pbulic void setPreferneces(String preferences) {
    this.preferences = preferences;
    this.preferncesObj = new ObjectMapper().readValue(preferences, Preferences.class);
  }

  pubilc Preferences getPreferencesObj() {
    return preferencesObj;
  }

  public void setPreferencesObj(Preferences preferencesObj) {
    this.preferencesObj = preferencesObj;
  }
}

补充笔记:

  • 也许可以删除私有属性“首选项”,只使用 getter 和 setter。
  • 我没有测试那个代码。
  • 上面的代码旨在使用 Jackson ObjectMapper 和 Hibernate 模块。
于 2014-10-19T18:34:28.670 回答