oracle 如果值是由触发器生成的,如何注释 Id 列?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7108229/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I annotate Id column if value is generated by a trigger?
提问by Zeemee
I have a setup with Oracle XE 10g, Hibernate 3.5, JPA 2.0. There is a simple table with a primary key, which is generated by a database trigger at insertion. The trigger gets the value from a sequence. The trigger/sequence construction was made by Oracle XE.
我安装了 Oracle XE 10g、Hibernate 3.5、JPA 2.0。有一个带有主键的简单表,它是在插入时由数据库触发器生成的。触发器从序列中获取值。触发器/序列构造由 Oracle XE 完成。
The actual question is: How do I get the current value of the Id in my entity after a EntityManager.persist?
I tried:
实际问题是:如何在 EntityManager.persist 之后获取实体中 Id 的当前值?
我试过:
@Id
private long id;
-> id is 0
;
-> id 是0
;
@Id
@Generated(GenerationTime.ALWAYS)
@Column(insertable = false, updatable = false)
private long id;
-> id is 0
;
-> id 是0
;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
-> Fails because Hibernate is trying to query the a sequence directly (which does not exist).
-> 失败,因为 Hibernate 试图直接查询 a 序列(它不存在)。
IDs are generated in the database in the first two approaches, but I don't have the value in my object.
前两种方法在数据库中生成 ID,但我的对象中没有该值。
回答by Christopher Yang
Contrary to @JB Nizet's comments, I can actually think of many reasons why we'd let a trigger assign IDs: execution of stored procs, manual execution of SQLs and running native queries in Hibernate, just to name a few.
与@JB Nizet 的评论相反,我实际上可以想到让触发器分配 ID 的许多原因:存储过程的执行、SQL 的手动执行以及在 Hibernate 中运行本机查询,仅举几例。
I personally found the following solution quite satisfactory. It lets Hibernate find the max ID and have it incremented every time an insert statement is called. But when the statement hits the database, the ID is ignored and overridden by the one generated by the trigger, so there's no uniqueness in a cluster problem:
我个人认为以下解决方案非常令人满意。它让 Hibernate 找到最大 ID 并在每次调用插入语句时增加它。但是当语句到达数据库时,ID 被忽略并被触发器生成的 ID 覆盖,因此集群问题中没有唯一性:
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
private Long id;
The biggest drawback is @GenericGenerator is a Hibernate annotation, so you lose JPA's portability. It's also not clear to the programmers that this ID is actually linked to a sequence.
最大的缺点是@GenericGenerator 是一个Hibernate 注释,所以你失去了JPA 的可移植性。程序员也不清楚这个 ID 实际上链接到一个序列。
Another alternative is to modify the trigger to only increment sequence when ID is null. See "Hibernate issue with Oracle Trigger for generating id from a sequence". In most cases, this is the best solution because it clearly shows the ID is linked to a sequence. My only gripe is it gives user/hibernate the option to insert any ID without actually inquiring the sequence in the first place.
另一种选择是将触发器修改为仅在 ID 为空时增加序列。请参阅“用于从序列生成 id 的 Oracle 触发器的休眠问题”。在大多数情况下,这是最好的解决方案,因为它清楚地显示 ID 与序列相关联。我唯一的抱怨是它为用户/休眠提供了插入任何 ID 的选项,而无需首先实际查询序列。
回答by atrain
Unless you are bound to the trigger, that seems like a level of obfuscation over the sequence, and it seems to go outside the normal Hibernate lifecycle. Why not directly call the sequence:
除非您绑定到触发器,否则这似乎是对序列的某种程度的混淆,并且似乎超出了正常的 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;
Then you will get the value back, as Hibernate is directly involved in the generation, and there isn't something happening after the fact.
然后你会得到这个值,因为 Hibernate 直接参与了生成,事后不会发生任何事情。
回答by Frank
You can exchange the db generated key within the Oracle session. For this, the insert trigger must call
您可以在 Oracle 会话中交换数据库生成的密钥。为此,插入触发器必须调用
dbms_session.set_identifier(new_id)
From your code, you can retrieve the new key value with the query
从您的代码中,您可以通过查询检索新的键值
String sql = "SELECT sys_context('USERENV', 'CLIENT_IDENTIFIER') FROM dual";
Query query = em.createNativeQuery(sql);
String new_id = (String) query.getSingleResult();
It is important to use the same EntityManager instance for persisting the new entity and retrieving the generated key value.
重要的是使用相同的 EntityManager 实例来持久化新实体并检索生成的键值。