在 Spring JPA 中持久化具有复合 id 的实体时出现错误且奇怪的 SQL

问题描述 投票:0回答:1

我有一个具有复合 id 的实体:


@Entity
@Table(name = "fs_metadata")
@IdClass(StoreFileMetadataId::class)
open class StoreFileMetadata(
    @Id
    @Column(name = "file_id", nullable = false)
    open var fileId: Long,

    @Id
    @Column(name = "key", nullable = false)
    open var key: String
) {

    @Column(name = "val_string")
    open var string: String? = null

    @Column(name = "val_int")
    open var number: Long? = null

    @Column(name = "val_boolean")
    open var boolean: Boolean? = null

    @Column(name = "val_date")
    open var date: LocalDateTime? = null
}

其中 id 类别是:


open class StoreFileMetadataId(var fileId: Long = 0L, var key: String = "") : Serializable {

    override fun toString() = "${fileId}.$key"
    override fun hashCode(): Int = Objects.hash(fileId, key)
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false

        other as StoreFileMetadataId

        return fileId == other.fileId &&
                key == other.key
    }

    companion object {
        private const val serialVersionUID = 5029017897184733803L
    }
}

我在实体

StoreFileMetadata
中使用
StoreFile

@Entity
@Table(name = "fs_file")
open class StoreFile {
    @Id
    @Column(name = "id", nullable = false)
    open var id: Long? = null

    // ...other fields

    @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.LAZY)
    @JoinColumn(name = "file_id")
    open var metadata: MutableSet<StoreFileMetadata> = mutableSetOf()
}

我创建了

StoreFile
的新实例,向其中添加一些元数据,然后尝试使用
StoreFileRepository.save()
:

保留它
@Repository
interface StoreFileRepository: CrudRepository<StoreFile, Long> 

我收到一个奇怪的错误:

could not execute statement [No value specified for parameter 2.] [update fs_metadata set file_id=null where file_id=? and file_id=? and key=?]

这里这个sql很奇怪,因为(1)它比较file_id两次,(2)它尝试将file_id清空,(3)它没有任何意义,因为orphanRemoval是true,无论如何我不删除。

一些注意事项:

  • 我也尝试使用
    @EmbeddedId
    方法并得到了同样的错误。
  • 我尽量避免使用无意义的基于序列的简单ID,因为这个表会很大,并且需要管理一个永远不会使用的索引。

我做错了什么?

hibernate kotlin jpa spring-data-jpa composite-key
1个回答
0
投票

我不太清楚为什么上面的方法不起作用,但我找到了解决方法。

最初我使用

@JoinColumn
来引用
StoreFileMetadata
中的
StoreFile
实体。它导致了上述错误。

首先我将参考更改为:

open class StoreFile {
  // ...other fields

  // Still not good as file_id is not refering to an StoreFile entity
  @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.LAZY)
    @JoinColumn(columnDefinition = "file_id", name = "file_id")
    open var metadata: MutableSet<StoreFileMetadata> = mutableSetOf()
}

所以我也必须在

StoreFileMetadata
中进行反向映射才能参考:

open class StoreFileMetadata {
    // ...other fields
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "file_id", insertable = false, updatable = false)
    open var storeFile: StoreFile? = null
}

它仍然是一个惰性且只读的参考,但它可以帮助 Hibernate 创建正确的 SQL。 现在我可以在

StoreFile

中引用它
open class StoreFile {
  // ...other fields

  @OneToMany(mappedBy = "storeFile", cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.LAZY)
    open var metadata: MutableSet<StoreFileMetadata> = mutableSetOf()
}

这也允许保留

StoreFile
级联元数据。

© www.soinside.com 2019 - 2024. All rights reserved.