简体   繁体   English

如何使用 JPA 和 Hibernate 将 MySQL JSON 列映射到 Java 实体属性

[英]How to map a MySQL JSON column to a Java entity property using JPA and Hibernate

I have MySQL column declared as type JSON and I have problems to map it with Jpa/Hibernate.我将 MySQL 列声明为JSON类型,并且在将其映射到 Jpa/Hibernate 时遇到问题。 I'm using Spring Boot on back-end.我在后端使用 Spring Boot。

Here is small part of my code:这是我的代码的一小部分:

@Entity
@Table(name = "some_table_name")
public class MyCustomEntity implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Column(name = "json_value")
private JSONArray jsonValue;

The program returns me an error and tells me that I can't map the column.该程序返回一个错误并告诉我我无法映射该列。

In mysql table the column is defined as:在 mysql 表中,列定义为:

json_value JSON NOT NULL; json_value JSON 非空;

I prefer to do this way:我更喜欢这样做:

  • Creating converter (attribute converter) from Map to String and vice versa.创建从 Map 到 String 的转换器(属性转换器),反之亦然。
  • Using Map to map mysql JSON column type in domain (entity) class使用Map映射域(实体)类中的mysql JSON列类型

The code is bellow.代码如下。

JsonToMapConverted.java JsonToMapConverted.java

@Converter
public class JsonToMapConverter 
                    implements AttributeConverter<String, Map<String, Object>> 
{
    private static final Logger LOGGER = LoggerFactory.getLogger(JsonToMapConverter.class);

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> convertToDatabaseColumn(String attribute)
    {
        if (attribute == null) {
           return new HashMap<>();
        }
        try
        {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(attribute, HashMap.class);
        }
        catch (IOException e) {
            LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.");
        }
        return new HashMap<>();
    }

    @Override
    public String convertToEntityAttribute(Map<String, Object> dbData)
    {
        try
        {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(dbData);
        }
        catch (JsonProcessingException e)
        {
            LOGGER.error("Could not convert map to json string.");
            return null;
        }
    }
}

Part of domain (entity-mapping) class域(实体映射)类的一部分

...

@Column(name = "meta_data", columnDefinition = "json")
@Convert(attributeName = "data", converter = JsonToMapConverter.class)
private Map<String, Object> metaData = new HashMap<>();

...

This solution perfectly works for me.这个解决方案非常适合我。

You don't have to create all these types manually, you can simply get them via Maven Central using the following dependency:您不必手动创建所有这些类型,您只需使用以下依赖项通过 Maven Central 获取它们:

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

For more info, check out the Hibernate Types open-source project .有关更多信息,请查看Hibernate Types 开源项目

Now, to explain how it all works.现在,解释这一切是如何运作的。

Assuming you have the following entity:假设您有以下实体:

@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
    name = "json", 
    typeClass = JsonType.class
)
public class Book {
 
    @Id
    @GeneratedValue
    private Long id;
 
    @NaturalId
    private String isbn;
 
    @Type(type = "json")
    @Column(columnDefinition = "json")
    private String properties;
 
    //Getters and setters omitted for brevity
}

Notice two things in the code snippet above:请注意上面代码片段中的两件事:

  • the @TypeDef is used to define a new custom Hibernate Type, json which is handled by the JsonType所述@TypeDef用于定义一个新的自定义Hibernate类型, json这是由处理JsonType
  • the properties attribute has a json column type and it's mapped as a String properties属性有一个json列类型,它被映射为一个String

That's it!就是这样!

Now, if you save an entity:现在,如果您保存实体:

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

Hibernate is going to generate the following SQL statement: 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
)

And you can also load it back and modify it:您还可以重新加载并修改它:

Book book = entityManager
    .unwrap(Session.class)
    .bySimpleNaturalId(Book.class)
    .load("978-9730228236");
     
book.setProperties(
    "{" +
    "   \"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 taking caare of the UPDATE statement for you: 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    
 
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

All code available on GitHub . GitHub 上提供的所有代码。

If the values inside your json array are simple strings you can do this:如果您的 json 数组中的值是简单的字符串,您可以这样做:

@Type( type = "json" )
@Column( columnDefinition = "json" )
private String[] jsonValue;

Heril Muratovic's answer is good, but I think the JsonToMapConverter should implement AttributeConverter<Map<String, Object>, String> , not AttributeConverter<String, Map<String, Object>> . Heril Muratovic 的回答很好,但我认为JsonToMapConverter应该实现AttributeConverter<Map<String, Object>, String> ,而不是AttributeConverter<String, Map<String, Object>> Here is the code that works for me这是对我有用的代码

@Slf4j
@Converter
public class JsonToMapConverter implements AttributeConverter<Map<String, Object>, String> {
    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> convertToEntityAttribute(String attribute) {
        if (attribute == null) {
            return new HashMap<>();
        }
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(attribute, HashMap.class);
        } catch (IOException e) {
            log.error("Convert error while trying to convert string(JSON) to map data structure.", e);
        }
        return new HashMap<>();
    }

    @Override
    public String convertToDatabaseColumn(Map<String, Object> dbData) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(dbData);
        } catch (JsonProcessingException e) {
            log.error("Could not convert map to json string.", e);
            return null;
        }
    }
}

For anyone can't make @J.对于任何人都无法制作@J。 Wang answer work :王回答工作:

Try add this dependency(it's for hibernate 5.1 and 5.0, other version check here )尝试添加此依赖项(适用于 hibernate 5.1 和 5.0,其他版本在此处检查)

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-5</artifactId>
    <version>1.2.0</version>
</dependency>

And add this line to the entity并将这一行添加到实体

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

So full version of the entity class :实体类的完整版本:

@Entity
@Table(name = "some_table_name")
@TypeDef(name = "json", typeClass = JsonStringType.class)
public class MyCustomEntity implements Serializable {

   private static final long serialVersionUID = 1L;

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;

   @Type( type = "json" )
   @Column( columnDefinition = "json" )
   private List<String> jsonValue;
}

I test the code with spring boot 1.5.9 and hibernate-types-5 1.2.0 .我使用 spring boot 1.5.9 和 hibernate-types-5 1.2.0 测试代码。

In Kotlin, the following variation/combination of the above suggestions worked for me:在 Kotlin 中,上述建议的以下变化/组合对我有用:

@Entity
@Table(name = "product_menu")
@TypeDef(name = "json", typeClass = JsonStringType::class)
data class ProductMenu(

    @Type(type = "json")
    @Column(name = "menu_json", columnDefinition = "json")
    @Convert(attributeName = "menuJson", converter = JsonToMapConverter::class)
    val menuJson: HashMap<String, Any> = HashMap()

) : Serializable



import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import org.slf4j.LoggerFactory
import java.io.IOException
import javax.persistence.AttributeConverter

class JsonToMapConverter : AttributeConverter<String, HashMap<String, Any>> {

    companion object {
        private val LOGGER = LoggerFactory.getLogger(JsonToMapConverter::class.java)
    }

    override fun convertToDatabaseColumn(attribute: String?): HashMap<String, Any> {
        if(attribute == null) {
            return HashMap()
        }
        try {
            val objectMapper = ObjectMapper()
            @Suppress("UNCHECKED_CAST")
            return objectMapper.readValue(attribute, HashMap::class.java) as HashMap<String, Any>
        } catch (e: IOException) {
            LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.")
        }
        return HashMap()
    }

    override fun convertToEntityAttribute(dbData: HashMap<String, Any>?): String? {
        return try {
            val objectMapper = ObjectMapper()
            objectMapper.writeValueAsString(dbData)
        } catch (e: JsonProcessingException) {
            LOGGER.error("Could not convert map to json string.")
            return null
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将JPA实体的JSON字符串列自动映射到Java对象 - Map JSON string column of a JPA entity to Java object automatically 如何将 TIMESTAMP 列映射到 ZonedDateTime JPA 实体属性? - How to map a TIMESTAMP column to a ZonedDateTime JPA entity property? 如何使用 H2、JPA 和 Hibernate 映射 JSON 列 - How to map a JSON column with H2, JPA, and Hibernate 如何 Spring JAVA(JPA/休眠)中的 map MySQL 时间戳字段 - How to map MySQL Timestamp field in Spring JAVA(JPA/Hibernate) 如何在没有 AttributeConverter 或 customUserType 的情况下使用 Hibernate 5.2.10 MySQL JSON 支持映射到 Java 实体类? - How to use Hibernate 5.2.10 MySQL JSON support without AttributeConverter or customUserType to map to Java Entity Class? 如何返回一个 Map,其中键是实体属性,值是具有 JPA 和 Hibernate 的实体 - How to return a Map where the key is an entity property and the value is the entity with JPA and Hibernate 如何使用 JPA 将映射 JSON 列映射到 Java 对象 - How to map a map JSON column to Java Object with JPA How to map a Java class property that is an object to a single JPA table column? - How to map a Java class property that is an object to a single JPA table column? 如何使用 Hibernate/JPA 将 JAVA 枚举映射到 Postgresql 枚举? - How to map JAVA enum to Postgresql Enum using Hibernate/JPA? 将 PostgreSQL JSON 列映射到 Hibernate 实体属性 - Mapping PostgreSQL JSON column to a Hibernate entity property
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM