首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用Spring Boot和Cassandra作为序数来持久化枚举?

如何用Spring Boot和Cassandra作为序数来持久化枚举?
EN

Stack Overflow用户
提问于 2019-04-30 07:26:27
回答 2查看 1.4K关注 0票数 2

在我的实体的枚举字段中,我添加了@CassandraType(type = DataType.Name.INT)。然而,在发送给Cassandra的语句中使用的不是枚举的序号,而是字符串表示。因此,我得到以下错误:

代码语言:javascript
复制
org.springframework.data.cassandra.CassandraInvalidQueryException: SessionCallback; CQL [INSERT INTO thing (thing_id,some_enum) VALUES (1,'Foo');]; Expected 4 or 0 byte int (3); nested exception is com.datastax.driver.core.exceptions.InvalidQueryException: Expected 4 or 0 byte int (3)

下面你可以找到一个最小的例子,重现这个问题。

我做错了什么?

test/src/main/kotlin/enumtest/Application.kt

代码语言:javascript
复制
package enumtest

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication


@SpringBootApplication
class Application

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}

test/src/main/kotlin/enumtest/SomeEnum.kt

代码语言:javascript
复制
package enumtest


enum class SomeEnum {
    Foo,
    Bar
}

test/src/main/kotlin/enumtest/Thing.kt

代码语言:javascript
复制
package enumtest

import com.datastax.driver.core.DataType
import org.springframework.data.cassandra.core.cql.PrimaryKeyType
import org.springframework.data.cassandra.core.mapping.CassandraType
import org.springframework.data.cassandra.core.mapping.Column
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn
import org.springframework.data.cassandra.core.mapping.Table


@Table("thing")
@Suppress("unused")
class Thing(

    @PrimaryKeyColumn(name = "thing_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
    var thingId: Long,

    @CassandraType(type = DataType.Name.INT)
    @Column("some_enum")
    var someEnum: SomeEnum

)

test/src/main/kotlin/enumtest/ThingRepository.kt

代码语言:javascript
复制
package enumtest

import org.springframework.data.cassandra.repository.CassandraRepository
import org.springframework.stereotype.Repository

@Repository
interface ThingRepository : CassandraRepository<Thing, Long>

test/src/main/resources/application.yml

代码语言:javascript
复制
spring:
  data:
    cassandra:
      contact-points: localhost
      port: 9142
      keyspace_name: enumtest

test/src/test/kotlin/enumtest/PersistenceTest.kt

代码语言:javascript
复制
package enumtest

import org.cassandraunit.spring.CassandraDataSet
import org.cassandraunit.spring.CassandraUnitDependencyInjectionTestExecutionListener
import org.cassandraunit.spring.EmbeddedCassandra
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.TestExecutionListeners
import org.springframework.test.context.junit4.SpringRunner

@RunWith(SpringRunner::class)
@SpringBootTest
@TestExecutionListeners(
    listeners = [CassandraUnitDependencyInjectionTestExecutionListener::class],
    mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
)
@CassandraDataSet(value = ["cql/cassandra_schema.cql"], keyspace = "enumtest")
@EmbeddedCassandra
class PersistenceTest {
    @Autowired
    lateinit var thingRepository: ThingRepository

    @Test
    fun `test save`() {
        thingRepository.save(Thing(1, SomeEnum.Foo))
        val things = thingRepository.findAll()
        Assert.assertEquals(1, things.size)
        val thing = things[0]
        Assert.assertEquals(SomeEnum.Foo, thing.someEnum)
    }
}

test/src/test/resources/cql/cassandra_schema.cql

代码语言:javascript
复制
CREATE KEYSPACE IF NOT exists enumtest
WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':1};

CREATE TABLE IF NOT exists enumtest.thing (
    thing_id     bigint,
    some_enum    int,
    PRIMARY KEY (thing_id)
);

test/build.gradle

代码语言:javascript
复制
plugins {
    id 'org.springframework.boot' version '2.1.4.RELEASE'
    id 'org.jetbrains.kotlin.jvm' version '1.3.30'
    id 'org.jetbrains.kotlin.plugin.spring' version '1.3.30'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
    maven { url "https://repository.apache.org/snapshots/" }
}

dependencies {
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-cassandra'
    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8'
    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect'

    testImplementation group: 'org.cassandraunit', name: 'cassandra-unit-spring', version: '3.5.0.1'
    testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}

compileKotlin {
    kotlinOptions {
        freeCompilerArgs = ['-Xjsr305=strict']
        jvmTarget = '1.8'
    }
}

compileTestKotlin {
    kotlinOptions {
        freeCompilerArgs = ['-Xjsr305=strict']
        jvmTarget = '1.8'
    }
}

下面是下载到实用实验的最小示例的完整版本:https://drive.google.com/open?id=1zzIDhbWycaj4WXrze2sAmw8xRPacA8Js

编辑:因为它似乎是一个bug,我刚刚打开了Jira问题

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-05-04 02:31:49

我已经尝试了很长一段时间,我似乎终于得到了它!

我遇到了和你和编解码器一样的问题.我不知道为什么不起作用。根据他们的文件,你做的完全正确。

所以我实现了我自己的卡桑德拉写转换器。见下文

代码语言:javascript
复制
@Configuration
class CassandraConfig(val cluster: Cluster){

    @Bean
    fun setCustomCassandraConversions() = CassandraCustomConversions(listOf(EnumWriteConverter.INSTANCE, EnumReadConverter.INSTANCE))

    @WritingConverter
    enum class EnumWriteConverter : Converter<Enum<MyEnum>, Int> {
        INSTANCE;
        override fun convert(source: Enum<MyEnum>) = source.ordinal
    }
     @ReadingConverter
    enum class EnumReadConverter : Converter<Int, Enum<MyEnum>> {
        INSTANCE;
        override fun convert(source: Int) = MyEnum.values()[source]
    }
}

在对Cassandra进行每次写入时,这都应该使用覆盖的转换器将它所看到的MyEnum类型的所有枚举转换为Int。这使您有可能为不同类型的enums拥有多个这样的值,可能出于某种原因,您希望从它们中写入其他自定义值,而不是总是转换所有枚举。

希望这行得通!

编辑注意在删除{}(例如在每个转换器上)并向CassandraCustomConversions注册ReadingConverter方面发生的变化

票数 2
EN

Stack Overflow用户

发布于 2019-05-23 14:15:36

这是自Spring版本的固定 2.1.5

但是,@CassandraType需要在Kotlin中显式地放置在getter上,因为否则在运行时看不到它。

在实践中,这只是意味着取代这一点:

代码语言:javascript
复制
    @CassandraType(type = DataType.Name.INT)
    var someEnum: SomeEnum

在此基础上:

代码语言:javascript
复制
    @get: CassandraType(type = DataType.Name.INT)
    var someEnum: SomeEnum
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55915849

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档