我面临的情况是,我有一个复杂的实体,我真的不确定 Kotlin/Spring/Hibernate 中在 DTO 和实体之间进行转换的最佳实践是什么,反之亦然。
所以可以说我有
ProductEntity
:
@Entity
@Table(name = "products")
data class ProductEntity(
// ...other fields
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id", referencedColumnName = "id")
val customer: CustomerEntity,
和一个
CustomerEntity
@Entity
@Table(name = "customers")
data class CustomerEntity(
var name: String,
var phoneNumber: String,
@OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
var contacts: Set<ContactEntity>? = null,
所以我的问题是,我应该如何在 DTO 中表示这种关系,因为我必须将它们转换为实体才能保留它们。
所以让我有一个像这样的 ProductDTO:
data class ProductDTO @JsonCreator constructor(
@JsonProperty("customerId") var customerId: UUID,
)
在这里,我可以将客户表示为与其数据库条目相对应的 UUID,当我将此 DTO 提供给函数来持久化它时,我必须从数据库中获取它:
productService.persistProduct(producDto)
fun persistProduct(ProductDTO productDto) {
val persistEntity = PersistEntity(
customer = customerRepository.fetch(productDto.customerId)
)
productRepository.save(peristEntity)
}
这种方法的唯一问题是,如果我首先获取实体,将其转换为 dto,更新 dto,然后尝试保留它,我会进行不必要的数据库调用,在这种情况下,我将两次获取相同的数据。
第二种方法是将所有数据直接保留在模型中,因此
ProductDto
将拥有其包含的复杂 dtos 中的所有数据:
data class ProductDTO @JsonCreator constructor(
@JsonProperty("customerName") var customerName: String,
@JsonProperty("customerPhoneNumber") var customerPhoneNumber: String,
@JsonProperty("contacts") var contacts: Set<ContactDto>,
)
但是将其转换回实体会使事情变得相当复杂,对吗?
productService.persistProduct(producDto)
fun persistProduct(ProductDTO productDto) {
val persistEntity = PersistEntity(
customer = CustomerEntity(name=productDto.customeName,
contacts = *map productDto.contacts to Set<ContactEntity>*)
)
productRepository.save(peristEntity)
}
对于如何处理这些复杂关系的映射有什么意见吗?
Kotlin 有一些映射器工具,例如 https://github.com/YanneckReiss/KConMapper
@KConMapper(toClasses = [CreateExampleDTO::class, UpdateExampleDTO::class])
data class ExampleEntity(
val uid: UUID = UUID.randomUUID(),
val name: String,
val timestamp: ZonedDateTime
)
val exampleEntity: ExampleEntity = ExampleEntity()
// For the create case:
val createExampleDTO: CreateExampleDTO = exampleEntity.toCreateExampleDTO()
// And for the update case:
val updateExampleDTO: UpdateExampleDTO = exampleEntity.toUpdateExampleDTO()
但就我个人而言,我想通过构建一个新的 DTO 来直接处理它。在现实世界的应用中,我们可以在 DTO 中使用不同的结构和命名。
val dto = ExampleDTO(
name=entity.fullname,
address= Address(street=entity.addreassStreet, zipCode=entity.addressZipCode)
...
)