spring-boot - Kotlin copy() 函数正在 JPA 实体上创建一个新的 Id,从而产生一个新行

标签 spring-boot kotlin spring-data-jpa

我在 spring Controller 上有一个更新方法,它接收请求并使用复制将内容复制到加载的实体中。一旦调用 copy() ,实体上的 id 属性就会更改为一个新属性。

@PutMapping("/{id}")
    fun update(@PathVariable id: UUID, @RequestBody request: UpdateSocietyRequest): ResponseEntity<SocietyUpdatedResponse> {
        val society = societyRepository.findById(id).orElse(null) ?: return notFound().build()
        val updatedSociety = society.copy(
                name = request.name,
                phone = request.phone,
                address = Address(
                        request.addressLine1,
                        request.addressLine2,
                        request.addressLine3,
                        request.city,
                        request.state,
                        request.zipCode
                )
        )
        societyRepository.save(updatedSociety)
        return ok(SocietyUpdatedResponse(updatedSociety.id, updatedSociety.name, updatedSociety.phone))
    }

实体.kt

@MappedSuperclass
@JsonIgnoreProperties(value = ["createdOn, updatedOn"], allowGetters = true)
@EntityListeners(AuditingEntityListener::class)
abstract class BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: UUID = UUID.randomUUID()

    @Column(nullable = false, updatable = false)
    @CreatedDate
    var createdOn: LocalDateTime = LocalDateTime.now()

    @Column(nullable = true)
    @LastModifiedDate
    var updatedOn: LocalDateTime? = null

    @Column(nullable = false, updatable = false)
    @CreatedBy
    var createdBy: String? = null

    @Column(nullable = true)
    @LastModifiedBy
    var updatedBy: String? = null
}

@Embeddable
data class Address(val addressLine1: String,
                   val addressLine2: String,
                   val addressLine3: String,
                   val city: String,
                   val state: String,
                   val zipCode: Int)

@Entity
data class Society(
        @NotNull
        val name: String,

        @NotNull
        val phone: String,

        @Embedded
        val address: Address
) : BaseEntity()

据我所知,复制不应该创建一个新对象,而是用请求中的新值更改现有对象。为什么要为 id 分配一个新的 UUID?

谢谢

最佳答案

根据 this link只有在括号之间定义的属性才会在 copy() 函数中使用,然后不会使用从父类(super class)继承的 id 和其他属性。我测试了它。

Properties Declared in the Class Body

Note that the compiler only uses the properties defined inside the primary constructor for the automatically generated functions. To exclude a property from the generated implementations, declare it inside the class body:

data class Person(val name: String) { var age: Int = 0 }

Only the property name will be used inside the toString(), equals(), hashCode(), and copy() implementations, and there will only be one component function component1(). While two Person objects can have different ages, they will be treated as equal.

不过,我的解决办法是:

不要使用copy() 函数。只需更改 society 的属性并保存即可。您可以更改 val 的属性,但不能更改引用(禁止使用 society = something)。

当您使用copy()时,它会在堆中生成一个新对象,它的引用是不同的(hashCode() 是不同的)。

所以我认为将 Society 类属性更改为 var 并使用以下代码一定很好:

@Entity
data class Society(
        @NotNull
        var name: String,

        @NotNull
        var phone: String,

        @Embedded
        var address: Address
) : BaseEntity()

...

@PutMapping("/{id}")
    fun update(@PathVariable id: UUID, @RequestBody request: UpdateSocietyRequest): ResponseEntity<SocietyUpdatedResponse> {
        val society = societyRepository.findById(id).orElse(null) ?: return notFound().build()
        society.name = request.name
        society.phone = request.phone
        society.address = Address(
                        request.addressLine1,
                        request.addressLine2,
                        request.addressLine3,
                        request.city,
                        request.state,
                        request.zipCode
                )
        )
        societyRepository.save(society)
        return ok(SocietyUpdatedResponse(society.id, society.name, society.phone))
    }

此外,我认为在数据类中使用继承会造成混淆,因此最好避免使用它。

关于spring-boot - Kotlin copy() 函数正在 JPA 实体上创建一个新的 Id,从而产生一个新行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52910153/

相关文章:

java - 部署Spring应用程序的多个实例

java - 如何知道日期是否在前 x 分钟内?

android - Firebase ML 套件给出 FirebaseMLException : Waiting for the text recognition model to be downloaded. 请稍候

java - 如何使用 Spring JPA 仅使用对象的某些部分编写查询

java - 为什么我必须在 spring data jpa 中将 @Modifying 与 @Transactional 一起使用?

Spring Security OAuth2 accessToken

Spring异常处理程序记录所有异常但返回原始响应

java - Spring Boot - 在部署时启动后台线程的最佳方式

java - 从 Java 到 Kotlin

java - SpringBoot 多数据源 - 仅在外部 Tomcat 容器中失败