如果触发器生成值,如何注释Id列?

时间:2011-08-18 13:32:23

标签: oracle hibernate jpa

我使用Oracle XE 10g,Hibernate 3.5,JPA 2.0进行了设置。有一个带主键的简单表,它由插入时的数据库触发器生成。触发器从序列中获取值。触发/序列构造由Oracle XE完成。

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

@Id
private long id;

- > id为0;

@Id
@Generated(GenerationTime.ALWAYS)
@Column(insertable = false, updatable = false)
private long id;

- > id为0;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;

- >失败,因为Hibernate试图直接查询序列(不存在)。

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

3 个答案:

答案 0 :(得分:7)

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

我个人发现以下解决方案相当令人满意。它允许Hibernate找到最大ID,并在每次调用insert语句时使其递增。但是当语句命中数据库时,ID会被触发器生成的ID忽略并覆盖,因此没有uniqueness in a cluster problem

    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;

最大的缺点是@GenericGenerator是一个Hibernate注释,因此你失去了JPA的可移植性。程序员也不清楚这个ID实际上是否与一个序列相关联。

另一种方法是修改触发器,使其仅在ID为null时递增序列。请参阅“Hibernate issue with Oracle Trigger for generating id from a sequence”。在大多数情况下,这是最好的解决方案,因为它清楚地显示ID与序列相关联。我唯一的抱怨是它为user / hibernate提供了插入任何ID的选项,而不是在第一时间实际查询序列。

答案 1 :(得分:2)

除非你受到触发器的限制,否则这似乎是对序列的一种混淆,它似乎超出了正常的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直接参与了这一代,事后并没有发生什么事情。

答案 2 :(得分:1)

您可以在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实例来保存新实体并检索生成的键值非常重要。