JPA:如何添加递归非空关系的第一个实体
如何添加递归非空关系的第一个实体?
当尝试对用户实体使用我的默认审核防护(EntityListener)时会出现问题。 Hibernate 无法插入第一个用户。这个例子是情况的简化:
@Entity
class User {
@Id @GeneratedValue
private Long id;
@Basic
private String name;
@ManyToOne(optional=false)
@JoinColumn(nullable=false,updatable=false)
private User createdBy;
// getters & setters
// equals & hashcode are based on name
}
我尝试过类似的操作:
User user = new User();
user.setName( "Some one" );
user.setCreatedBy( user );
Hibernate 失败,根异常是:
com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert the value NULL into
column 'createdby_id', table 'mydb.user'; column does not allow nulls. INSERT fails.
我知道几种解决方法:手动插入第一个实体(SQL 插入)或设置 nullable=true。首先很烦人,其次是完整性失败点(需要自定义审计侦听器和数据库触发器)。有更好的选择吗?或者,换句话说:是否有仅 JPA 的解决方案?
我的平台是:SQL Server 2008 和 Hibernate 3.6 作为 JPA2 提供程序。
编辑:起初,我使用的是persist()。我尝试了 merge()
,它可以做出更智能的猜测,但没有区别。我也尝试了 CascadeType.MERGE 。
How to add the first entity of recursive non-null relation?
The trouble occurs when trying to use my default audit guard (EntityListener) for user entities. Hibernate isnt able to insert first user. The example is simplification of situation:
@Entity
class User {
@Id @GeneratedValue
private Long id;
@Basic
private String name;
@ManyToOne(optional=false)
@JoinColumn(nullable=false,updatable=false)
private User createdBy;
// getters & setters
// equals & hashcode are based on name
}
And I have tried something like:
User user = new User();
user.setName( "Some one" );
user.setCreatedBy( user );
Hibernate fails and root exception is:
com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert the value NULL into
column 'createdby_id', table 'mydb.user'; column does not allow nulls. INSERT fails.
I know several workarounds: insert first entity manually (SQL insert) or set nullable=true. First is just annoying and second is fail point of integrity (custom audit listener & db trigger required). Is there better options? Or, in the other words: is there JPA-only solution?
My platform is: SQL Server 2008 and Hibernate 3.6 as JPA2 provider.
Edit: At first, I was using persist()
. I tried merge()
which could make more intelligent guess but no difference. And I tried CascadeType.MERGE
too.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
非空约束要求您在引用字段中插入 user.id,但如果您已将 id 字段设置为自动生成,则直到插入后才知道该值。要解决此问题,您可以使用序列来生成 @Id,
并通过获取该序列的下一个值并将两个字段设置为该值来插入第一个用户。对于来自 JPA 的本机 SQL 查询,这看起来像:
这有点笨拙,但只需调用一次。所有其他用户都将以正常方式保留(使用 SEQ_USER 作为 @Id 的生成器序列)
或者,您可以编写自己的 SequenceGenerator 来执行此操作:
在 User 中,您可以将该生成器设置为:
然后
按预期工作。
The not null constraint mandates that you insert the user.id in the reference field, but if you have set the id field to be autogenerated, that value is not known until after the insert. To solve this, you could use a sequence to generate the @Id
and insert the first user by fetching the next value of that sequence, and setting both fields to that value. With a native SQL query from JPA this looks like:
which is a little kludgy but has to be called only once. All other users would be persisted the normal way (using SEQ_USER as Generator sequence for the @Id)
Alternatively, you could write your own SequenceGenerator do just that:
In User, you qould set that generator as:
and then
works as expected.