首页 > 解决方案 > JPA 实体和表 ID 作为字符串

问题描述

我正在使用 MySQL,并且有一个表包含与其他表中的 id 相关的数据 json 数据,而不是中间表

目前有 3 个表:Customers、Assets 和 Table XXX,其中有 3 列:id、name 和 myData。这是一个示例行:

1, "Some name",

[
    {"customerId": 1, "assets": {"active": [10, 12, 13], "inactive": [15, 16]}}",
    {"customerId": 2, "assets": {"active": [40, 42], "inactive": [19]}}"

]

顺便说一句,我不能改变设计:(

以下是实体:

@Table(name = "xxx")
class XXX {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id")
   private Long id;
   private String name;
   String myData;
}

@Table(name = "assets")
class Asset {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id")
   private Long id;
   private String name;
}

@Table(name = "customers")
class Customer {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id")
   private Long id;

   private String name;
}

但是,我希望实体 XXX 正确映射实体并拥有客户和资产数据,类似于:

@Table(name = "xxx")
class XXX {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id")
   private Long id;
   private String name;
   //maybe some awesome annotation here?
   List<CustomerAssetsItem> customerAssetsItemsActive;

   //maybe some awesome annotation here?
   List<CustomerAssetsItem> customerAssetsItemsInactive;
}

CustomerAssetsItem 看起来像:

class CustomerAssetsItem {
   Customer customer;
   List<Asset> assets;
}

JPA甚至可以吗?或者我应该只创建一个解析 json 字符串的新服务,运行我需要的所有查询来构建层次结构?谢谢!

标签: hibernatespring-bootjpaspring-data-jpa

解决方案


有可能,看这个例子:JSON Attribute converter

您所要做的就是提供一个AttributeConverter将 JSON 字符串映射到您的列表或其他任何内容的方法。

在您的实体上,您必须通过注释转换器类@Converter

@Table(name = "xxx")
class XXX {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id")
   private Long id;
   private String name;

   @Converter(converter = CustomerAssetsConverter.class)
   List<CustomerAssetsItem> customerAssetsItems;
}

而且你必须提供你自己的转换器,这只是一个草稿。您需要添加一个 JSON 对象映射器。此外,如果您想解析 JSON 中的客户 ID 引用,您需要自己的反序列化器,用于customerId: 1映射执行查询以获取该客户。请参阅此示例:杰克逊自定义反序列化器

可能不想解析引用,因为它们可能会导致大量查询,而且您很可能需要调整很多设置以不以无限循环结束。

我建议启用二级缓存并适当地使用@Transactional。

@Converter
public class CustomerAssetsConverter implements AttributeConverter<CustomerAssetsItem, String> {

    //Add object mapper and repository

    @Override
    public String convertToDatabaseColumn(CustomerAssetsItem item) {
        String itemJSON = null;
        try {
            itemJSON = objectMapper.writeValueAsString(item);
        } catch (final JsonProcessingException e) {

        }
        return itemJSON;
    }

    @Override
    public Map<String, Object> convertToEntityAttribute(String itemJSON) {
        CustomerAssetsItem item = null;
        try {
            item = objectMapper.readValue(itemJSON, CustomerAssetsItem.class);
        } catch (final IOException e) {

        }
        return item;
    }
}

推荐阅读