【问题标题】:JPA: Override Auto generated ID for composite key?JPA:为复合键覆盖自动生成的 ID?
【发布时间】:2020-11-15 15:37:41
【问题描述】:

出于文档目的添加此问题,并检查是否有任何替代解决方案。

我有一个实体,它有一个使用 @IdClass 定义的复合键

data class TemplateId(var id: Long? = null, var version: Int = 0) : Serializable

@Entity
@IdClass(TemplateId::class)
data class Template(
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    var id: Long? = null,

    @Id
    @Column(name = "version")
    var version: Int

    //Other columns
)

想法是为Template 的不同版本使用相同的ID。插入新模板时,使用序列生成器按预期工作。 但是,当我尝试插入具有相同 ID 的新版本行时,@GeneratedValue 会覆盖给定值并自动增量为新值。 JPA: Override Auto generated ID中提到的解决方案 不工作。

【问题讨论】:

  • 只是一个小建议:为什么不使用 Envers?开箱即用支持 AFAIK 这样的场景(每个 id 具有多个修订的实体)

标签: java hibernate kotlin jpa spring-data-jpa


【解决方案1】:

我尝试了以下选项,但都没有成功。

  • 如问题中所述,不能使用@GeneratedValue,因为它会替换给定值

  • 无法用自定义生成器 (@GenericGenerator) 替换 @SequenceGenerator,不适用于复合键。它尝试将 Long 值转换为 IdClass TemplateId

  • 我正在使用 Postgres,因此尝试将列类型 SERIAL 用于 id。这不适用于复合键上的 IDENTITY GenerationType。存在一个问题:HHH-9662

  • 不能使用 NULL 值的数据库自动增量,postgres 给出约束冲突错误

  • id 列上的"insertable"=false/ "updatable"=false 不适用于 @Id

  • 类似地尝试使用 hibernate 的 @DynamicInsert 以便在插入查询中跳过空列值,但即使这样也不适用于 @Id

最后不得不重写 Spring 的 JpaRepositorysave 函数才能使其工作

interface CustomTemplateRepository<S> {
    fun <E: S> save(entity: E): E
    fun <E: S> saveAndFlush(entity: E): E
}


class TemplateRepositoryImpl(
    private val jdbcTemplate: NamedParameterJdbcTemplate,
    @PersistenceContext private val entityManager: EntityManager
) : CustomTemplateRepository<Template> {
    override fun <E : Template> save(entity: E): E {
        if(entity.id == null)
            entity.id = jdbcTemplate.queryForObject("select nextval('sequence_generator')", 
                              mutableMapOf<String, Any>(), Long::class.java)
        entityManager.persist(entity)
        return entity
    }

    override fun <E : Template> saveAndFlush(entity: E): E {
        return save(entity).also {
            entityManager.flush()
        }
    }
}

【讨论】:

    猜你喜欢
    • 2012-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-19
    • 2010-12-21
    • 2014-08-16
    • 1970-01-01
    相关资源
    最近更新 更多