sql >> Database teknologi >  >> RDS >> PostgreSQL

SpringBoot+Kotlin+Postgres og JSONB:org.hibernate.MappingException:Ingen dialekttilknytning for JDBC-typen

Jeg foreslår min løsning i en pull-anmodning

Ideen er at ændre Entitet til:

import com.example.demo.pojo.SamplePojo
import com.vladmihalcea.hibernate.type.json.JsonBinaryType
import com.vladmihalcea.hibernate.type.json.JsonStringType
import org.hibernate.annotations.Type
import org.hibernate.annotations.TypeDef
import org.hibernate.annotations.TypeDefs
import javax.persistence.*

@Entity
@Table(name = "tests")
@TypeDefs(
        TypeDef(name = "json", typeClass = JsonStringType::class),
        TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)
)
data class SampleEntity (
    @Id @GeneratedValue
    val id: Long?,
    val name: String?,

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    var data: Map<String, Any>?
) {

    /**
     * Dependently on use-case this can be done differently:
     * https://stackoverflow.com/questions/37873995/how-to-create-empty-constructor-for-data-class-in-kotlin-android
     */
    constructor(): this(null, null, null)
}
  1. Hver enhed skal enten have en standardkonstruktør eller have standarder for alle dens parametre
  2. I stedet for at gemme POJO, gem som Map<String, Any> type

Da vi har fuld kontrol over, hvad der vil være i POJO i forretningslogik, vil den eneste manglende brik være at konvertere POJO til Map og Map til POJO

SamplePojo implementering

data class SamplePojo(
        val payload: String,
        val flag: Boolean
)  {
    constructor(map: Map<String, Any>) : this(map["payload"] as String, map["flag"] as Boolean)

    fun toMap() : Map<String, Any> {
        return mapOf("payload" to payload, "flag" to flag)
    }
}

Dette er snarere en løsning, men det giver os mulighed for at arbejde med alle strukturer på dybdeniveau.

P.S. Jeg har bemærket, at du bruger Serializer og omdefineret equals, toString, hashCode . Du har ikke brug for dette, hvis du bruger data class .

OPDATERING:

Hvis du har brug for en mere fleksibel struktur end Map<String, Any> , kan du bruge JsonNode . Kodeeksempel

Enhed:

import com.fasterxml.jackson.databind.JsonNode
import com.vladmihalcea.hibernate.type.json.JsonBinaryType
import com.vladmihalcea.hibernate.type.json.JsonStringType
import org.hibernate.annotations.Type
import org.hibernate.annotations.TypeDef
import org.hibernate.annotations.TypeDefs
import javax.persistence.*

@Entity
@Table(name = "tests")
@TypeDefs(
        TypeDef(name = "json", typeClass = JsonStringType::class),
        TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)
)
data class SampleJsonNodeEntity (
        @Id @GeneratedValue
        val id: Long?,
        val name: String?,

        @Type(type = "jsonb")
        @Column(columnDefinition = "jsonb")
        var data: JsonNode?
) {

    /**
     * Dependently on use-case this can be done differently:
     * https://stackoverflow.com/questions/37873995/how-to-create-empty-constructor-for-data-class-in-kotlin-android
     */
    constructor(): this(null, null, null)
}

Skift enhed i lager:

import com.example.demo.entity.SampleJsonNodeEntity
import org.springframework.data.jpa.repository.JpaRepository

interface SampleJsonNodeRepository: JpaRepository<SampleJsonNodeEntity, Long> {
}

Tester for begge tilgange:

import com.example.demo.DbTestInitializer
import com.example.demo.entity.SampleJsonNodeEntity
import com.example.demo.entity.SampleMapEntity
import com.example.demo.pojo.SamplePojo
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit4.SpringRunner


@RunWith(SpringRunner::class)
@SpringBootTest
@ContextConfiguration(initializers = [DbTestInitializer::class])
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class SampleRepositoryTest {

    @Autowired
    lateinit var sampleMapRepository: SampleMapRepository

    @Autowired
    lateinit var sampleJsonNodeRepository: SampleJsonNodeRepository

    lateinit var dto: SamplePojo
    lateinit var mapEntity: SampleMapEntity
    lateinit var jsonNodeEntity: SampleJsonNodeEntity

    @Before
    fun setUp() {
        dto = SamplePojo("Test", true)
        mapEntity = SampleMapEntity(null,
                "POJO1",
                dto.toMap()
        )

        jsonNodeEntity = SampleJsonNodeEntity(null,
            "POJO2",
                jacksonObjectMapper().valueToTree(dto)
        )
    }

    @Test
    fun createMapPojo() {
        val id = sampleMapRepository.save(mapEntity).id!!
        assertNotNull(sampleMapRepository.getOne(id))
        assertEquals(sampleMapRepository.getOne(id).data?.let { SamplePojo(it) }, dto)
    }

    @Test
    fun createJsonNodePojo() {
        val id = sampleJsonNodeRepository.save(jsonNodeEntity).id!!
        assertNotNull(sampleJsonNodeRepository.getOne(id))
        assertEquals(jacksonObjectMapper().treeToValue(sampleJsonNodeRepository.getOne(id).data, SamplePojo::class.java), dto)
    }

}


  1. Sådan opretter du pivottabel i PostgreSQL

  2. Hvordan udfylder man manglende datoer i MySQL?

  3. Funktion til at fjerne accenter i postgreSQL

  4. Et følelsesløst logisk blik på SQL Server-navnekonventioner