我在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?
答案 0 :(得分:1)
查看headCatalogFacade.save(headCatalog);
- 它有一个写入数据库的对象的returnType。只需写下headCatalog = headCatalogFacade.save(headCatalog);
即可。当你得到它的ID时,它将不再是null。您可以实现自己的save()方法来更改该行为。
如果您的IDE自动生成该方法,请仔细查看它调用的方法。 em.merge(Object object)
具有您作为参数传递的对象的returnType。
我总是喜欢按如下方式为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);
}
答案 1 :(得分:0)
当JPA设置传递给实体的实体的ID时,取决于您的生成策略和提供者。一些策略允许预分配,因此可以在持久调用上设置ID。但是,在大多数情况下,只有在事务提交或上下文同步到数据库(em.flush)之后才设置它是安全的。您没有显示方法的事务范围,因此您可能只需要在create方法中调用em.flush,以便传入的实体在headCatalogFacade.create方法返回之前设置其ID,以便在设置时始终设置它。你打算用它。
合并返回您传入的托管副本。如果您传入的是新实体,它将永远不会设置其ID - 只有当上下文同步时,托管实体才会设置其ID(除非它可以是预分配)。如果您处于相同的上下文中,则甚至不需要保存调用,因为第一次调用create / persist会导致该实例被管理 - 因此返回的托管实例与您传入的实例完全相同。如果需要合并,那么这意味着您要将实体序列化到headCatalogFacade或从headCatalogFacade序列化,因此需要从每个调用返回实体以便能够看到结果 - 而且我还猜测数据库在此方法的每次传递中显示重复的,未填充的HeadCatalog行。
对于Id可能不是空消息,您需要显示您获取该消息的确切位置,以及headCatalogFacade代码以便理解它。