使用 eclipselink 保留和合并实体后无法获取 ID
can't get ID after persisting and merging an entity using eclipselink
我在 Centos 7 下的 Netbeans 8.1 中使用 Glassfish 4.1.1 和 EclipseLink 2.5.2 MySQL。
我的实体是:
@Entity
@Table(name = "headCatalog")
@XmlRootElement
public class HeadCatalog implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "headCatalog")
@TableGenerator(name = "headCatalog", table = "sequenceNumbers",
pkColumnName = "tableName", valueColumnName = "sequenceNumber",
pkColumnValue = "headCatalog")
@Basic(optional = false)
@NotNull
@Column(name = "id")
private Integer id;
@Size(max = 45)
@Column(name = "brand")
private String brand;
@Size(max = 45)
@Column(name = "model")
private String model;
@Basic(optional = false)
@NotNull
@Column(name = "arc")
private double arc;
....
我正在尝试使用以下方式将数据加载到其中:
headCatalog = new HeadCatalog();
headCatalogFacade.create(headCatalog);
headCatalog.setBrand(brand);
headCatalog.setModel(model);
headCatalog.setArc(arc);
headCatalogFacade.save(headCatalog);
headCatalogFacade.flush();
//headCatalogFacade.refresh(headCatalog);
headCatalogID = headCatalog.getId();
....
当我 运行 执行此操作时,headCatalogID 返回 null(注意,创建调用 em.persist 并保存调用 em.merge;这是 netbeans 生成的样板代码)。我已经设置了一个断点,刷新后 ID 值在数据库中。如果我取消对刷新的评论,我会收到一条消息,指出 headCatalog 已分离。
我正在使用@TableGenerator 作为解决方法;如果我使用
@GeneratedValue (GenerationType.SEQUENCE or strategy = GenerationType.IDENTITY)
我得到:
Severe: com.wjrust.sprinklere.entities.HeadCatalog.id may not be null
如果我执行查询并重新加载实体,那么 ID 就在那里,但由于我不知道 ID 是什么,所以创建查询是一个问题。
那么,保存实体后如何获取ID呢?
JPA 何时设置传递给持久化的实体的 ID 取决于您的生成策略和提供者。一些策略允许预分配,因此可以在持久调用中设置 ID。但在大多数情况下,只有在事务提交或上下文同步到数据库 (em.flush) 之后,您才可以安全地假设它已设置。您没有显示方法的事务范围,因此您可能只需要在创建方法中调用 em.flush,以便传入的实体在 headCatalogFacade.create 方法 return 之前设置其 ID s,以便在您计划使用它时始终设置它。
合并 returns 您传入内容的托管副本。如果您传入的是新实体,则永远不会设置其 ID - 只有托管实体会在上下文时设置其 ID同步(除非它可以预先分配)。如果您处于同一上下文中,则甚至不需要调用保存,因为第一次调用 create/persist 会导致该实例被管理 - 因此托管实例 returned 与您传递的实例相同以任何方式。如果需要合并,那么这意味着您正在序列化您的实体 to/from headCatalogFacade,因此需要 return 从您的每个调用返回实体才能看到结果 - 我'我还猜测数据库在此方法的每次传递中都显示重复的、未填充的 HeadCatalog 行。
对于 Id 可能不为空的消息,您需要显示您从何处获取该消息,以及要理解的 headCatalogFacade 代码。
看看 headCatalogFacade.save(headCatalog);
- 它有一个写入数据库的对象的 returnType。只写headCatalog = headCatalogFacade.save(headCatalog);
。当您获得它的 ID 时,它将不再为空。您可以实现自己的 save() 方法来更改该行为。
如果您的 IDE 自动生成了该方法,请仔细查看它调用的方法。 em.merge(Object object)
具有您作为参数传递的对象的返回类型。
我总是喜欢按如下方式实现我的 EJB 的基本方法:
public <T> T save(T o) {
if (o == null) throw new EntityNotFoundException("Dao::save does not allow null values.");
return em.merge(o);
}
public void remove(Object o) {
if (o == null) throw new EntityNotFoundException("Dao::remove does not allow null values.");
em.remove(em.merge(o));
}
public <T> T find(Class<T> clazz, Object id) {
return em.find(clazz, id);
}
我在 Centos 7 下的 Netbeans 8.1 中使用 Glassfish 4.1.1 和 EclipseLink 2.5.2 MySQL。
我的实体是:
@Entity
@Table(name = "headCatalog")
@XmlRootElement
public class HeadCatalog implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "headCatalog")
@TableGenerator(name = "headCatalog", table = "sequenceNumbers",
pkColumnName = "tableName", valueColumnName = "sequenceNumber",
pkColumnValue = "headCatalog")
@Basic(optional = false)
@NotNull
@Column(name = "id")
private Integer id;
@Size(max = 45)
@Column(name = "brand")
private String brand;
@Size(max = 45)
@Column(name = "model")
private String model;
@Basic(optional = false)
@NotNull
@Column(name = "arc")
private double arc;
....
我正在尝试使用以下方式将数据加载到其中:
headCatalog = new HeadCatalog();
headCatalogFacade.create(headCatalog);
headCatalog.setBrand(brand);
headCatalog.setModel(model);
headCatalog.setArc(arc);
headCatalogFacade.save(headCatalog);
headCatalogFacade.flush();
//headCatalogFacade.refresh(headCatalog);
headCatalogID = headCatalog.getId();
....
当我 运行 执行此操作时,headCatalogID 返回 null(注意,创建调用 em.persist 并保存调用 em.merge;这是 netbeans 生成的样板代码)。我已经设置了一个断点,刷新后 ID 值在数据库中。如果我取消对刷新的评论,我会收到一条消息,指出 headCatalog 已分离。
我正在使用@TableGenerator 作为解决方法;如果我使用
@GeneratedValue (GenerationType.SEQUENCE or strategy = GenerationType.IDENTITY)
我得到:
Severe: com.wjrust.sprinklere.entities.HeadCatalog.id may not be null
如果我执行查询并重新加载实体,那么 ID 就在那里,但由于我不知道 ID 是什么,所以创建查询是一个问题。
那么,保存实体后如何获取ID呢?
JPA 何时设置传递给持久化的实体的 ID 取决于您的生成策略和提供者。一些策略允许预分配,因此可以在持久调用中设置 ID。但在大多数情况下,只有在事务提交或上下文同步到数据库 (em.flush) 之后,您才可以安全地假设它已设置。您没有显示方法的事务范围,因此您可能只需要在创建方法中调用 em.flush,以便传入的实体在 headCatalogFacade.create 方法 return 之前设置其 ID s,以便在您计划使用它时始终设置它。
合并 returns 您传入内容的托管副本。如果您传入的是新实体,则永远不会设置其 ID - 只有托管实体会在上下文时设置其 ID同步(除非它可以预先分配)。如果您处于同一上下文中,则甚至不需要调用保存,因为第一次调用 create/persist 会导致该实例被管理 - 因此托管实例 returned 与您传递的实例相同以任何方式。如果需要合并,那么这意味着您正在序列化您的实体 to/from headCatalogFacade,因此需要 return 从您的每个调用返回实体才能看到结果 - 我'我还猜测数据库在此方法的每次传递中都显示重复的、未填充的 HeadCatalog 行。
对于 Id 可能不为空的消息,您需要显示您从何处获取该消息,以及要理解的 headCatalogFacade 代码。
看看 headCatalogFacade.save(headCatalog);
- 它有一个写入数据库的对象的 returnType。只写headCatalog = headCatalogFacade.save(headCatalog);
。当您获得它的 ID 时,它将不再为空。您可以实现自己的 save() 方法来更改该行为。
如果您的 IDE 自动生成了该方法,请仔细查看它调用的方法。 em.merge(Object object)
具有您作为参数传递的对象的返回类型。
我总是喜欢按如下方式实现我的 EJB 的基本方法:
public <T> T save(T o) {
if (o == null) throw new EntityNotFoundException("Dao::save does not allow null values.");
return em.merge(o);
}
public void remove(Object o) {
if (o == null) throw new EntityNotFoundException("Dao::remove does not allow null values.");
em.remove(em.merge(o));
}
public <T> T find(Class<T> clazz, Object id) {
return em.find(clazz, id);
}