意外的JPA行为-在应更新时删除

时间:2020-09-07 21:15:54

标签: spring hibernate jpa

所以我正在处理一些Spring Data JPA代码,实现是Hibernate。我创建了两个具有OneToMany关系的实体。这是实体:

@Entity
@Table(name = "clients")
data class Client (
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Long,
        @Column(unique = true)
        val name: String,
        @Column(unique = true)
        val clientKey: String,
        val clientSecret: String,
        val enabled: Boolean,
        val accessTokenTimeoutSecs: Int,
        val refreshTokenTimeoutSecs: Int,
        val authCodeTimeoutSecs: Int,

        @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "clientId")
        val clientRedirectUris: List<ClientRedirectUri>
)

@Entity
@Table(
        name = "client_redirect_uris",
        uniqueConstraints = [
                UniqueConstraint(columnNames = [
                        "clientId",
                        "redirectUri"
                ])
        ]
)
data class ClientRedirectUri (
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Long,
        val clientId: Long,
        val redirectUri: String
)

所以,我的想法是每次我保存Client时,应该更新ClientRedirectUri引用。但是,这没有正确发生。这是我的持久性代码:

authClient = TestData.createClient(accessTokenTimeoutSecs, refreshTokenTimeoutSecs).copy(
        name = validClientName,
        clientKey = validClientKey,
        clientSecret = "{bcrypt}$encodedSecret"
)
authClient = clientRepo.save(authClient)
val clientRedirectUri = ClientRedirectUri(0, authClient.id, "http://somewhere.com/authcode/code")
authClient = authClient.copy(clientRedirectUris = listOf(clientRedirectUri))
authClient = clientRepo.save(authClient)
clientRepo.save(authClient.copy(clientRedirectUris = listOf(clientRedirectUri.copy(redirectUri = "uri_1"))))

我首先创建authClient变量,然后将其持久保存到数据库中。现在已经为其分配了ID,我将该ID用于ClientRedirectUri实体的外键关系。设置好子实体并将其添加到authClient后,我再次将其保存()。到目前为止,一切都很完美。

然后,作为测试,我使用Kotlin copy()方法创建了原始对象的克隆,但是随后我将clientRedirectUris属性替换为带有新URI的新列表。这里的目标是一成不变地修改实体,然后在数据库中对其进行更新。

然后导致异常:

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FKCW186RT6R4DRLEKPENRLQDNL5: PUBLIC.CLIENT_REDIRECT_URIS FOREIGN KEY(CLIENT_ID) REFERENCES PUBLIC.CLIENTS(ID) (1)"; SQL statement:
delete from clients where id=? [23503-200]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

实际上,它不是在进行更新操作,而是先删除Client引用,然后再插入一个新的引用。这不是我想要的,我希望它进行更新。

现在,经过大量的实验,我发现有些困惑。让我们对代码示例的最后一行进行更改,然后返回保存的实体:

authClient = clientRepo.save(authClient.copy(clientRedirectUris = listOf(clientRedirectUri.copy(redirectUri = "uri_1"))))

仅需进行一些细微的更改即可更改行为,并且JPA / Hibernate最终完美地处理了事情。原始的Client实体(根据记录的SQL)不会被触摸,而是只处理ClientRedirectUri实体的插入/删除操作。

为什么会发生这种情况,将来如何预防?

0 个答案:

没有答案
相关问题