在 jpa 中保存对象之前如何知道 id
Posted
技术标签:
【中文标题】在 jpa 中保存对象之前如何知道 id【英文标题】:How do I know the id before saving an object in jpa 【发布时间】:2012-09-26 09:47:00 【问题描述】:我有一个新对象。我想在保存之前知道 id 。可能吗?或者还有另一种方法?我使用 jpa 作为 orm 和 oracle 作为数据库。
@Id
@Basic(optional = false)
@Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "woTypeSeq")
private Long id;
我的实体中有一个代码字段。如果用户没有为code
字段输入值,我想将代码设置为实体的ID。如果我持久化实体,当然我可以获取id并将代码值设置为id,但这是额外的查询数据库。
我想做这样的事情
if(entity.getCode()==null)
entity.setCode(entity.getId);
jpaDao.saveOrUpdate(entity);
【问题讨论】:
您可以避免使用@GeneratedValue,自己使用生成器获取值并将其“手动”设置为实体 我不想手动将其设置为实体。如果我从 oracle 获取 id 的下一个值并将其设置为新实体的 id,是否合理? 【参考方案1】:使用@GeneratedValue 类型ID,您无法提前知道该值(在实际编写之前)。然而,一旦你持久化你的 Bean,id 字段将被填充到该 bean 实例中,你可以获取它而无需对其进行额外的查询。换句话说:
MyEntiry myEnt = new MyEntity(); //the id field is null now
entityManager.persist(myEnt);//the id field is populated in myEnt now
Long id = myEnt.getId();
此外,根据您的 EntityManager
的配置方式,您可能还需要先提交事务(手动),然后才能获得该 ID。
根据评论更新
如果您想在保存和/或更新实体之前对其进行拦截和处理,您可以使用 JPA LifeCycle Listeners(如果您使用的是 JPA 版本 2):Handling JPA lifecycle event using listeners and callbacks。
基本上你可以在你的 bean 中创建一个 validate()
方法,用 @PrePersist
和 @PreUpdate
对其进行注释并在其中进行验证(如果代码为空,则将其设置为 id 的值)
每第二条评论更新
是的,老实说,我刚刚才想到:如果 id 是自动生成的,它可能会在 pre-persist 事件之后被填充,这样当你的 pre-persist 代码被执行时,你仍然不知道什么id 是(您可能还注意到,在示例中您链接到 id 不是自动生成的,而是手动设置的)。
在这种情况下,您可以做的是向您的实体添加一个名为 isCodeEmpty
的布尔字段(用 @Transient
注释,因此它不会被持久化)(如果没有特别初始化,默认情况下为 false)。然后在 @PrePersist
带注释的方法中检查代码字段的值是否为空,如果是,则将布尔值设置为 true。然后重构 setId(...)
方法,以便(除了设置 id 字段)它会检查这个布尔值,如果为 true,则将 code 字段的值设置为 id 字段的值:
public class YourEntity
@Transient
private boolean isCodeEmpty;
public void setId(Whatever id)
this.id = id;
if(isCodeEmpty)
this.code = id;
//if necessary:
//this.isCodeEmpty = false;
@PrePersist
public void validate()
if(code == null || code.isEmpty())
isCodeEmpty = true;
【讨论】:
感谢您的回复。我更新了我的问题。您可以检查一下吗? 我已经尝试过实体监听器。但在 prepersist 中,id 值为 null。我不知道为什么它是 null。我这样实现 = java2s.com/Tutorial/Java/0355__JPA/… 你有什么建议或想法吗?非常感谢 你的想法很棒,但是在 prePersist setId() 方法不起作用之后。我照你说的做了。我调试它,但 setId 方法未执行,代码字段未设置。Prepersist 正在工作。【参考方案2】:经过长时间的研究,我终于找到了解决方案。
其实,如果你在jpa中使用sequence generator,在存入数据库之前肯定是无法获取entity的id的,因为下一个id是由数据库sequence分配的。
如果您使用自定义生成器,有一种获取 id 的方法,您可以在保存之前获取 id。这是简单的实现:
public class CustomGenerator extends IdentityGenerator implements Configurable
private IdentifierGenerator defaultGenerator;
public Serializable generate(SessionImplementor session, Object object) throws HibernateException
Long idValue = (Long)defaultGenerator.generate(session, object);
//idValue will be assigned your entity id
return idValue;
@Override
public void configure(Type type, Properties params, Dialect d) throws MappingException
DefaultIdentifierGeneratorFactory dd = new DefaultIdentifierGeneratorFactory();
dd.setDialect(d);
defaultGenerator = dd.createIdentifierGenerator("sequence", type, params);
对 id 字段使用 CustomGenerator:
@Id
@Basic(optional = false)
@Column(name = "ID", nullable = false)
@GenericGenerator(name = "seq_id", strategy = "com.yoncabt.abys.core.listener.CustomGenerator", parameters = @Parameter(name = "sequence", value = "II_FIRM_DOC_PRM_SEQ") )
@GeneratedValue(generator = "seq_id")
private Long id;
【讨论】:
能告诉我可配置接口的封装吗?我看到很多包都包含这个,但没有一个有方法 configure(Type type, Properties params, Dialect d) throws MappingException 这个ID可以用于prepersist吗??【参考方案3】:只需按照这些步骤,您将在完成交易之前获得 id。
第 1 步通过使用名为 @EntityListeners
的注释在您的实体级别添加一个实体侦听器。
@Id
@Basic(optional = false)
@Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "woTypeSeq")
@EntityListeners(SomeLinstener.class)
private Long id;
第二步
public class SomeLinstener
@PostPersist
public void userPostPersist(YourEntity obj)
try
obj.getId();
catch(Exception e)
这将为您提供一个由您的生成器生成的 ID,您可以在任何需要的地方重复使用它,这将在单个事务中提供。
希望这对其他人有帮助。
【讨论】:
【参考方案4】:以下是适合我的解决方案:
@Id
@GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "my_seq" )
@SequenceGenerator( name = "my_seq", sequenceName = "my_seq" )
@Access( AccessType.PROPERTY )
private Long id;
@Column( name = "CODE", nullable = false, updatable = false )
private Long code;
public void setId(Long id)
this.id = id;
if (code == null)
code = id;
重要的部分是放置@javax.persistence.Access( AccessType.PROPERTY )
注解,这使得Hibernate 使用getter 和setter 来访问id 字段。没有它,当@Id 注解直接放在字段上而不是字段 getter 上时,Hibernate 使用基于字段的访问策略(不使用 getter 和 setter)。链接:https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/domain/access.htmlhiber
【讨论】:
以上是关于在 jpa 中保存对象之前如何知道 id的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Data JPA 保存具有手动分配标识符的实体?
弹簧数据 JPA。如何从 findAll() 方法中仅获取 ID 列表
JPA:如何避免简单地加载对象,以便将其 ID 存储在数据库中?