JPA:覆盖复合键的自动生成ID?

huangapple 未分类评论48阅读模式
英文:

JPA: Override Auto generated ID for composite key?

问题

为了文档目的并检查是否有任何替代解决方案,我有一个实体,其复合键是使用@IdClass定义的。

  1. data class TemplateId(var id: Long? = null, var version: Int = 0) : Serializable
  2. @Entity
  3. @IdClass(TemplateId::class)
  4. data class Template(
  5. @Id
  6. @Column(name = "id")
  7. @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
  8. @SequenceGenerator(name = "sequenceGenerator")
  9. var id: Long? = null,
  10. @Id
  11. @Column(name = "version")
  12. var version: Int
  13. //其他列
  14. )

我的想法是对Template的不同版本使用相同的ID。在插入新模板时,使用序列生成器的效果如预期。但当我尝试插入具有相同ID的新版本行时,@GeneratedValue会覆盖给定的值并自动增加到新值。这里提到的解决方案不起作用。

英文:

Adding this question for documentation purpose, and to check if there is any alternative solution.

I have an entity which has a composite key defined using @IdClass

  1. data class TemplateId(var id: Long? = null, var version: Int = 0) : Serializable
  2. @Entity
  3. @IdClass(TemplateId::class)
  4. data class Template(
  5. @Id
  6. @Column(name = "id")
  7. @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
  8. @SequenceGenerator(name = "sequenceGenerator")
  9. var id: Long? = null,
  10. @Id
  11. @Column(name = "version")
  12. var version: Int
  13. //Other columns
  14. )

Idea is to have same ID for different versions of the Template. Using Sequence generator works as expected while inserting new template.
But when I try to insert a new version row with same ID, @GeneratedValue overrides the given value and autoincrements to new value.
Solution mentioned in JPA: Override Auto generated ID
does not work.

答案1

得分: 0

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

  • 如问题中所述,无法使用 @GeneratedValue,因为它会替换给定的值。

  • 不能用自定义生成器(@GenericGenerator)替换 @SequenceGenerator,因为它在复合键中不起作用。它试图将 Long 值转换为 IdClass TemplateId

  • 我正在使用 Postgres,所以尝试将 id 的列类型设置为 SERIAL。但是这在复合键上使用 IDENTITY GenerationType 时不起作用。存在一个现有的问题:HHH-9662

  • 不能使用带有 NULL 值的数据库自增,Postgres 会报违反约束的错误。

  • "insertable"=false / "updatable"=falseid 列上不适用于 @Id 列。

  • 类似地,尝试使用 Hibernate 的 @DynamicInsert,这样它将在插入查询中跳过空列值,但即使在 @Id 列中也不起作用。

最终不得不覆盖 Spring 的 JpaRepositorysave 函数,使其工作起来。

  1. interface CustomTemplateRepository<S> {
  2. fun <E: S> save(entity: E): E
  3. fun <E: S> saveAndFlush(entity: E): E
  4. }
  5. class TemplateRepositoryImpl(
  6. private val jdbcTemplate: NamedParameterJdbcTemplate,
  7. @PersistenceContext private val entityManager: EntityManager
  8. ) : CustomTemplateRepository<Template> {
  9. override fun <E : Template> save(entity: E): E {
  10. if (entity.id == null)
  11. entity.id = jdbcTemplate.queryForObject("select nextval('sequence_generator')",
  12. mutableMapOf<String, Any>(), Long::class.java)
  13. entityManager.persist(entity)
  14. return entity
  15. }
  16. override fun <E : Template> saveAndFlush(entity: E): E {
  17. return save(entity).also {
  18. entityManager.flush()
  19. }
  20. }
  21. }
英文:

I tried out following options and none worked.

  • As mentioned in the question, cannot use @GeneratedValue as it replaces the given value

  • Cannot replace @SequenceGenerator with custom generator (@GenericGenerator), doesn't work with composite key. It tries to cast Long value to IdClass TemplateId

  • I am using Postgres, so tried using column type SERIAL for id. This does not work with IDENTITY GenerationType on composite key. There is an existing issue : HHH-9662

  • Cannot use DB auto-increment with NULL value, postgres gives constraint violation error

  • &quot;insertable&quot;=false/ &quot;updatable&quot;=false on id column does not work for @Id columns

  • Similarly tried using hibernate's @DynamicInsert so that it will skip null column values in insert query, but even that doesn't work with @Id

Finally had to override the save function of Spring's JpaRepository to make it work

  1. interface CustomTemplateRepository&lt;S&gt; {
  2. fun &lt;E: S&gt; save(entity: E): E
  3. fun &lt;E: S&gt; saveAndFlush(entity: E): E
  4. }
  5. class TemplateRepositoryImpl(
  6. private val jdbcTemplate: NamedParameterJdbcTemplate,
  7. @PersistenceContext private val entityManager: EntityManager
  8. ) : CustomTemplateRepository&lt;Template&gt; {
  9. override fun &lt;E : Template&gt; save(entity: E): E {
  10. if(entity.id == null)
  11. entity.id = jdbcTemplate.queryForObject(&quot;select nextval(&#39;sequence_generator&#39;)&quot;,
  12. mutableMapOf&lt;String, Any&gt;(), Long::class.java)
  13. entityManager.persist(entity)
  14. return entity
  15. }
  16. override fun &lt;E : Template&gt; saveAndFlush(entity: E): E {
  17. return save(entity).also {
  18. entityManager.flush()
  19. }
  20. }
  21. }

huangapple
  • 本文由 发表于 2020年7月26日 12:35:15
  • 转载请务必保留本文链接:https://java.coder-hub.com/63096128.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定