Oracle 如果值是由触发器生成的,我如何注释Id列?

Oracle 如果值是由触发器生成的,我如何注释Id列?,oracle,hibernate,jpa,Oracle,Hibernate,Jpa,我已经安装了Oracle XE 10g、Hibernate 3.5、JPA 2.0。有一个带有主键的简单表,它是由数据库触发器在插入时生成的。触发器从序列中获取值。触发器/序列构造由Oracle XE完成 实际问题是:在EntityManager.persist之后,如何获取实体中Id的当前值? 我试过: ->id为0 @Id @Generated(GenerationTime.ALWAYS) @Column(insertable = false, updatable = false) priv

我已经安装了Oracle XE 10g、Hibernate 3.5、JPA 2.0。有一个带有主键的简单表,它是由数据库触发器在插入时生成的。触发器从序列中获取值。触发器/序列构造由Oracle XE完成

实际问题是:在EntityManager.persist之后,如何获取实体中Id的当前值?
我试过:

->id为
0

@Id
@Generated(GenerationTime.ALWAYS)
@Column(insertable = false, updatable = false)
private long id;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
->id为
0

@Id
@Generated(GenerationTime.ALWAYS)
@Column(insertable = false, updatable = false)
private long id;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
->失败,因为Hibernate正在尝试直接查询a序列(该序列不存在)


在前两种方法中,ID是在数据库中生成的,但我的对象中没有该值。

除非您绑定到触发器,否则这看起来像是序列上的混淆级别,并且似乎超出了正常的Hibernate生命周期。为什么不直接调用序列:

@SequenceGenerator(name="alias_for_my_sequence", sequenceName="seq_name_in_oracle")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="alias_for_my_sequence")
@Id
private Long id;

然后,您将获得返回的值,因为Hibernate直接参与了生成,并且在生成之后不会发生任何事情。

您可以在Oracle会话中交换db生成的密钥。为此,插入触发器必须调用

dbms_session.set_identifier(new_id)
从代码中,可以通过查询检索新的键值

String sql = "SELECT sys_context('USERENV', 'CLIENT_IDENTIFIER') FROM dual";
Query query = em.createNativeQuery(sql);
String new_id = (String) query.getSingleResult();

使用同一个EntityManager实例来持久化新实体和检索生成的键值是很重要的。

与@JB Nizet的评论相反,我实际上可以想到让触发器分配ID的许多原因:执行存储过程、手动执行SQL和在Hibernate中运行本机查询,仅举几个例子

我个人认为以下解决方案相当令人满意。它允许Hibernate查找最大ID,并使其在每次调用insert语句时递增。但当语句命中数据库时,该ID将被忽略并被触发器生成的ID覆盖,因此没有:

最大的缺点是@GenericGenerator是Hibernate注释,因此您失去了JPA的可移植性。程序员也不清楚这个ID是否真的链接到了一个序列


另一种选择是,当ID为null时,将触发器修改为仅递增序列。见“”。在大多数情况下,这是最好的解决方案,因为它清楚地显示ID链接到序列。我唯一的不满是,它让用户/hibernate可以选择插入任何ID,而不必首先询问序列。

谢谢,但是:触发点是Oracle自动生成递增PK值的方法。如果我去掉了这一点,我将失去通过直接查询数据库轻松插入行的可能性。第二,如果我像你的建议中那样注释,我就不能轻易地切换到Derby进行单元测试:(…我需要的是一个注释,上面写着:“只取DB生成的内容”。谷歌搜索了这一点,根据粗略的检查,似乎其他用户已经成功引用了Hibernate的Oracle序列。下面是一个例子:。在Derby问题上,针对不同于部署平台的DB平台进行单元测试不是最佳做法,可能会导致单元测试与部署平台之间的不一致d运行时行为。@Mulmoth:除非有另一个字段唯一地标识该行,否则Hibernate如何从数据库中获取生成的ID,因为标识刚刚插入的行的唯一方法是它的ID,它不知道。简言之,获取ID需要ID。你的触发器是一个非常糟糕的主意。请看看这个例子:它展示了如何实现一个custome hibernate生成器来检索插入后的id。对于我来说,当触发器创建的数据库中的实际id为90时,在persist之后返回id 94。