2011-08-18 31 views
7

我使用Oracle XE 10g,Hibernate 3.5,JPA 2.0进行安装。有一个带有主键的简单表,由插入时的数据库触发器生成。触发器从序列中获取值。触发器/序列构造由Oracle XE完成。如果通过触发器生成值,我如何注释Id列?

实际的问题是:如何在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在前两种方法中在数据库中生成,但我没有在我的对象中的值。

回答

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的直接参与的产生,并没有什么事后发生。

+0

谢谢,但是:触发器是Oracle自动生成递增PK值的方法。如果我摆脱了这一点,我将失去通过对数据库的直接查询轻松插入行的可能性。第二,如果我在你的建议中注释,我不能轻易地转换到德比进行单元测试:(...我需要的是一个注释,它说:“只要拿出数据库产生的东西。” – Zeemee

+0

谷歌搜索这一点,和基于粗略的检查,似乎其他用户已经成功地从Hibernate中重新获得了Oracle序列,下面是一个例子:https://forum.hibernate.org/viewtopic.php?p=2442821。在Derby的问题上,unit针对不同于部署平台的数据库平台进行测试并不是最佳实践,可能会导致单元测试和运行时行为之间的不一致。 – atrain

+2

@Mulmoth:除非有另一个字段唯一标识行,否则Hibernate如何获得因为识别刚刚插入的行的唯一方法就是它的ID,它不知道,简而言之,需要ID来获得ID,你的触发器是一个非常糟糕的想法。 –

1

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

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实例为坚持新的实体是非常重要的并检索生成的密钥值。

7

与@JB Nizet的评论相反,我可以想到为什么我们要让触发器分配ID的许多原因:存储过程的执行,SQL的手动执行以及在Hibernate中运行本机查询等等。

我个人发现下面的解决方案比较满意。它让Hibernate找到最大ID并在每次调用插入语句时增加它。但是,当语句访问数据库,该ID将被忽略,由触发产生的一个重写,所以没有uniqueness in a cluster problem

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

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

另一种替代方法是修改触发器,使其仅在ID为空时递增序列。参见“Hibernate issue with Oracle Trigger for generating id from a sequence”。在大多数情况下,这是最好的解决方案,因为它清楚地显示ID与序列相关联。我唯一的抱怨是它给用户/休眠选项插入任何ID没有实际查询序列的第一位。

+0

请看看这个例子:http://developer-should-know.com/post/82479486933/how-to-use-oracle-before-insert-trigger-for-id它显示了如何实现custome hibernate生成器,用于检索id帖子插入。 –