Kotlin 数据类:如何为嵌入的文档生成 MongoDB ObjectId

纪伯伦

我正在使用 Spring Boot 和 Kotlin 构建 API。我正在尝试在 MongoDB 中按以下方式生成结构。

在此处输入图片说明

我了解到在 MongoDb 中不存在实体之间关系的概念,所以我将使用嵌入文档的策略。也就是说,在 Proyecto 中嵌入 Reunión,在 Reunión 中嵌入 Participante。

我有一个名为Proyectoand的主类NewProyecto,它包含一个类型为 reuniones 的列表作为属性NewReunion我使用两个不同的类来创建和返回数据。

项目.kt

@Document(collection = "proyectos")
@TypeAlias("proyecto")
data class Proyecto (
        @Id
        val id: String,
        val nombre: String,
        val area: String,
        val fecha:String,
        val reuniones: List<Reunion>?
){}

@Document(collection = "proyectos")
@TypeAlias("newproyecto")
data class NewProyecto (
        @Id
        val id: String?,//Es posiblemente nulo porqué se crea automáticamente
        var nombre: String,
        var area: String,
        var fecha:String,
        var reuniones: List<NewReunion>?
){}

现在,为了创建“团聚”,我有两个类,ReunionNewReunion. 对应于创建 MongoDB 嵌入文档的类是NewReunion.

新团圆.kt

@Document
data class Reunion(
        val objetivo: String,
        val fecha: String,
        val participantes: List<Participante>?
) {}

@Document
data class NewReunion(
        var id: String? = ObjectId().toHexString(),
        var fecha: String,
        var participantes: List<NewParticipante>?
) {}

这是我有问题的地方。我想为这个NewReunion生成一个 ObjectId ,以便嵌入其中的每个对象都有一个id. 的问题是,ObjectId ().ToHexString()不产生在该类型的对象中的任何时间值NewReunion是建立,但是其他数据objetivo,并fecha填充有来自POST请求中的数据。

我如何发送信息。

我通过POST. 此请求由名为的控制器处理ProyectoController.kt

项目控制器.kt

@PostMapping("/")
fun createProyecto(@RequestBody newProyecto: NewProyecto): NewProyecto = proyectoService.createProyecto(newProyecto)

项目库.kt

interface ProyectoRepository : MongoRepository<Proyecto, String> {
    fun findById(id: ObjectId): Proyecto
    override fun findAll(): List<Proyecto>
    fun insert(proyecto: NewProyecto): NewProyecto
    fun save(proyect: Proyecto): Proyecto
    fun deleteById(id: ObjectId)
}

项目服务.kt

@Service("proyectoService")
class ProyectoServiceImpl : ProyectoService {
    @Autowired
    lateinit var proyectoRepository: ProyectoRepository

    //Obtener un proyecto
    override fun findById(id: ObjectId): Proyecto = proyectoRepository.findById(id)

    //Obtener todos los proyectos
    override fun findAll(): List<Proyecto> = proyectoRepository.findAll()

    //Crear un proyecto
    override fun createProyecto(newProyecto: NewProyecto): NewProyecto = proyectoRepository.insert(newProyecto)

    //Actualizar un proyecto
    override fun updateProyecto(proyecto: Proyecto):Proyecto = proyectoRepository.save(proyecto)

    //Eliminar un proyecto
    override fun deleteProyecto(id:ObjectId) = proyectoRepository.deleteById(id)
}

使用邮递员发布:

发送信息我使用邮递员,我通过以下方式发送请求。 在此处输入图片说明

在创建 new 时Proyecto,我返回它以查看返回结果的结果id=null,但所有其他字段都分配了相应的值:

在此处输入图片说明

现在,我尝试初始化 NewReunion 类的所有构造函数参数以查看发生了什么。

data class NewReunion(
        @Id
        var id: String? = ObjectId().toHexString(),
        var objetivo: String = "",
        var fecha: String = ""
) {}

的值id与其他值一起正确生成。正是这种行为,我不明白为什么我需要初始化NewReunion类的构造函数参数

带有初始化参数的 POST 结果。

在此处输入图片说明

构建.gradle

buildscript {
    ext.kotlin_version = '1.2.71'
    ext {
        kotlinVersion = '1.2.71'
        springBootVersion = '2.0.6.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'

group = 'com.gibranlara'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}
compileTestKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}

repositories {
    mavenCentral()
}

configurations {
    providedRuntime
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" // Required for Kotlin integration
    compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
    compile "org.springframework.boot:spring-boot-starter-data-mongodb"
    compile 'org.springframework.boot:spring-boot-starter-web'
}
安德烈·阿图斯

您使用的库可能不是用 Kotlin 编写的。

Kotlin 生成一个合成构造函数,在调用实际构造函数之前加载默认值,例如

   // Java 
   public NewReunion(String var1, String var2, String var3, int var4, DefaultConstructorMarker var5) {
      if ((var4 & 1) != 0) {
         var1 = ObjectId().toHexString();
      }
      this(var1, var2, var3);
   }

The library is likely doing one of the following:

  • Calling the default constructor, then calling set[Property] matching the annotations/convention.
  • Calling the closest match constructor: NewReunion(@Nullable String id, @NotNull String objetivo, @NotNull String fecha) with NewReunion(null, "objetivo", "fecha")

If you define your class as such:

data class NewReunion @JvmOverloads constructor(
    var id: String? = "",
    var objetivo: String,
    var fecha: String
)

You will get additional constructors e.g.

// Java
public NewReunion(@NotNull String objetivo, @NotNull String fecha)

If your library is using the first option then you may need to lazy initialize the id field in a getter (also convert data class to normal class).

An Aside

Most of these kind of problems stem from devs using the same object model for communication and business logic. Whenever I see a nullable id on an entity it like a clarion call that bugs are afoot.

你从外部来源获得的任何数据(即使它来自你控制的服务器)都应该被视为是你最邪恶的敌人把它放在那里,但许多开发人员只是吸收它并在它出现时使用它。

如果你没有类似的东西

val cleanData = validate(inputData)

在从输入层过渡到业务层之前,您正在为未来的尴尬做好准备。

输入层是:

  • 用户界面
  • 网页服务
  • 任何来自您直接控制范围之外的东西

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章