英文:
JPA: Override Auto generated ID for composite key?
问题
为了文档目的并检查是否有任何替代解决方案,我有一个实体,其复合键是使用@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
//其他列
)
我的想法是对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
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
)
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 值转换为 IdClassTemplateId
。 -
我正在使用 Postgres,所以尝试将
id
的列类型设置为SERIAL
。但是这在复合键上使用 IDENTITY GenerationType 时不起作用。存在一个现有的问题:HHH-9662。 -
不能使用带有 NULL 值的数据库自增,Postgres 会报违反约束的错误。
-
"insertable"=false / "updatable"=false
在id
列上不适用于@Id
列。 -
类似地,尝试使用 Hibernate 的
@DynamicInsert
,这样它将在插入查询中跳过空列值,但即使在@Id
列中也不起作用。
最终不得不覆盖 Spring 的 JpaRepository
的 save
函数,使其工作起来。
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()
}
}
}
英文:
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 IdClassTemplateId
-
I am using Postgres, so tried using column type
SERIAL
forid
. 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
-
"insertable"=false/ "updatable"=false
onid
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
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()
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论