Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map Java/Kotlin string array and Postgres SQL array with JPA and hibernate

I have a field in Postgres in array type:

 categories    | text[]         |           |          |

How can I declare the field in the entity class?

I have tried below in Product.kt file but it throws error [ERROR]:ERROR: relation "product_categories" does not exist

@ElementCollection
@Column(name = "categories")
var categories: List<String>? = emptyList()

My purpose is to save the string array as one field of the entity, I am not trying to do anything related "One to Many".

If you know any Java version solution and it works, I will accept the answer as well. Thanks

like image 782
Haifeng Zhang Avatar asked Oct 22 '20 05:10

Haifeng Zhang


People also ask

How to map a PostgreSQL array with Hibernate?

3. Custom Hibernate Types Hibernate supports custom types to map a user-defined type into SQL queries. Therefore, we can create custom types to map a PostgreSQL array with Hibernate for storing/fetching data. First, let's create the CustomStringArrayType class implementing Hibernate's UserType class to provide a custom type to map the String array:

How to map SQL arrays to string and int arrays in JPA?

However, neither JPA nor Hibernate support SQL arrays by default, and we want to map these arrays to a String and int Java arrays, respectively. So, we are going to use the Hibernate Types project to achieve this goal. The first thing you need to do is to set up the following Maven dependency in your project pom.xml configuration file:

How to map PostgreSQL array columns to Java list entity attributes?

Because Hibernate ORM does not support ARRAY column types, we need to use the Hibernate Types open-source project to be able to map PostgreSQL ARRAY columns to Java List entity attributes. After adding the Hibernate Types dependency, you can use the ListArrayType as illustrated by the following JPA entity mapping:

Can you map SQL arrays to JPA entity attributes when using hibernate?

In this article, we are going to see how you can map SQL arrays to JPA entity attributes when using Hibernate. Hibernate custom Types allow you to map all sorts of database-specific column types, like IP address, JSON columns, bit sets, or SQL arrays.


2 Answers

Adam's answer works for projects written in Java. As my project is written in Kotlin, I share my version below and hope it helps and people can use it right away other than spending time to convert:

Useful resource: How to map Java and SQL arrays with JPA and Hibernate

Postgres:

alter table product add column categories text[];

Gradle:

implementation("com.vladmihalcea:hibernate-types-52:2.10.0")

Product.kt

import com.vladmihalcea.hibernate.type.array.StringArrayType
import org.hibernate.annotations.*
import javax.persistence.*
import javax.persistence.Entity


@TypeDefs(
    TypeDef(name = "string-array", typeClass = StringArrayType::class)
)
@Entity
class Product(
        var name: String,

        @Type(type = "string-array")
        @Column(name = "categories", columnDefinition = "text[]")
        var categories: Array<String>? = arrayOf(),
)

There're 2 differences between Java and Kotlin:

  1. The array type in Kotlin is Array<String> other than String[], I tried List<String> as well but it didn't work.
  2. TypeDefs,TypeDef is different, no @ sign.
like image 127
Haifeng Zhang Avatar answered Oct 19 '22 20:10

Haifeng Zhang


This won't work with @ElementCollection as it will always try to use another table. What you need is a custom type instead. For this you'll need this dependency:

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

then you can define your own types:


import com.vladmihalcea.hibernate.type.array.StringArrayType

@TypeDefs({
    @TypeDef(
        name = "string-array", 
        typeClass = StringArrayType.class
    )
})
@Entity
class YourEntity {

    @Type( type = "string-array" )
    @Column(
        name = "categories", 
        columnDefinition = "character varying[]"
    )
    var categories: Array<String>;
}

I haven't tried this with a List though, as this maps to an Array. More info in this answer.

like image 2
Adam Arold Avatar answered Oct 19 '22 21:10

Adam Arold