Kotlin+ Sping Boot 中实体到DTO转换的最佳实践

bjg7j2ky  于 2023-03-03  发布在  Kotlin
关注(0)|答案(1)|浏览(236)

我熟悉几种解决这个问题的方法,但可能我错过了一些真正有用的东西:
我有一个API实体:

data class SomeApiEntity(
    val id: Long? = null,

    @field:NotBlank
    val name: String,

    val someIntData: Long,
)

和Spring JPA实体:

@Entity(name = "some_entity")
class SomeEntity(
    @field:NotBlank
    @Column(name = "name", nullable = false)
    val name: String,

    @Column(name = "some_int_data", nullable = false)
    val someIntData: Long,
) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    var id: Long? = null
}

现在我需要想出一种方法来将这些实体从一个转换为另一个。
最流行的解决方案是在这些实体中实现方法,如下所示:
这个是SomeApiEntity

fun toApiEntity(): SomeApiEntity = SomeApiEntity(
        id,
        name,
        intData,
    )

这个是SomeEntity类的。

fun toEntity(): SomeEntity = SomeEntity(
        name,
        intData
    )

但我发现这个解决方案不成功,可扩展性很差。
大型实体,特别是带有转换逻辑的实体,特别是如果在那里使用了其他Spring Bean,就可以进行测试了。好吧,像这里这样的小型实体与大型实体统一起来了。
我知道在Spring中实现Converter<S, T>接口的解决方案,但它也很糟糕,因为它只解决了单向转换,并在将来必须编写的代码量方面给我们带来了很小的开销。

pzfprimi

pzfprimi1#

我不确定是否有特别针对Spring的最佳实践,但对于Android开发,我倾向于不在类本身上创建这些方法(例如,将Entity转换为Entity类上的DTO的方法)。我不这样做的原因是我将两个类一起tightly couple,而且我也不认为Entity's reposability知道如何将其自身Map到域,反之亦然。
我通常会创建一个扩展函数来做同样的事情,但是在一个单独的文件中,如下所示:

fun SomeDTO.toApiEntity() = SomeApiEntity(
   id = id,
   name = name,
   intData = intData,
)

如果需要,您可以像测试任何其他方法一样测试它:

@Test
fun `GIVEN SomeDTO object WHEN toSomeApiEntity called THEN must return SomeEntity with same values`() {
   // GIVEN
   val name = "Jonh"
   val id = 1L
   val intData = 254

   val someDTO = SomeDTO(id = id, name = name, intData = intData)
   val expectedSomeEntity = SomeEntity(id = id, name = name, intData = intData)

   // WHEN
   val actualSomeEntity = someDTO.toSomeApiEntity()

   // THEN
   Assert.AsserEquals(expectedSomeEntity.id, actualSomeEntity.id)
   Assert.AsserEquals(expectedSomeEntity.name, actualSomeEntity.name)
   Assert.AsserEquals(expectedSomeEntity.intData, actualSomeEntity.intData)
}

相关问题