我了解JPA并且有任务创建数据库并为其插入一些值.我想知道如何找出最近插入的对象的ID是什么,所以我找到了一种方法,我需要使用EntityManager的flush方法.
不幸的是我得到了
Null or zero primary key encountered in unit of work clone
我使用上述方法时的异常.我认为问题在于我的数据库在自动增量上设置了所有ID(我使用ORACLE 11G Express),因此在提交之前它具有空值并且它回滚事务.
我能做些什么来修复它?
这是DB(ID是自动增量[oracle中的序列和触发器]):
- public class Client {
- public static void main(String[] args) {
- EntityManagerFactory emf =
- Persistence.createEntityManagerFactory("JpaIntroductionPU");
- EntityManager em = emf.createEntityManager();
- EntityTransaction et = em.getTransaction();
- et.begin();
- Address ad1 = new Address();
- ad1.setStreet("Skaraktki");
- ad1.setCode("64-340");
- em.persist(ad1);
- em.flush();
- System.out.println(ad1.getAId());
- et.commit();
- }
- }
Address class
- @Entity
- @Table(name = "ADDRESS")
- @NamedQueries({
- @NamedQuery(name = "Address.findAll",query = "SELECT a FROM Address a"),@NamedQuery(name = "Address.findByAId",query = "SELECT a FROM Address a WHERE a.aId = :aId"),@NamedQuery(name = "Address.findByStreet",query = "SELECT a FROM Address a WHERE a.street = :street"),@NamedQuery(name = "Address.findByCode",query = "SELECT a FROM Address a WHERE a.code = :code")})
- public class Address implements Serializable {
- private static final long serialVersionUID = 1L;
- // @Max(value=?) @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
- @Id
- @Basic(optional = false)
- @Column(name = "A_ID")
- private BigDecimal aId;
- @Basic(optional = false)
- @Column(name = "STREET")
- private String street;
- @Basic(optional = false)
- @Column(name = "CODE")
- private String code;
- @OneToOne(cascade = CascadeType.ALL,mappedBy = "aId")
- private Employee employee;
- @OneToOne(cascade = CascadeType.ALL,mappedBy = "aId")
- private Department department;
- public Address() {
- }
- public Address(BigDecimal aId) {
- this.aId = aId;
- }
- public Address(BigDecimal aId,String street,String code) {
- this.aId = aId;
- this.street = street;
- this.code = code;
- }
- public BigDecimal getAId() {
- return aId;
- }
- public void setAId(BigDecimal aId) {
- this.aId = aId;
- }
- public String getStreet() {
- return street;
- }
- public void setStreet(String street) {
- this.street = street;
- }
- public String getCode() {
- return code;
- }
- public void setCode(String code) {
- this.code = code;
- }
- public Employee getEmployee() {
- return employee;
- }
- public void setEmployee(Employee employee) {
- this.employee = employee;
- }
- public Department getDepartment() {
- return department;
- }
- public void setDepartment(Department department) {
- this.department = department;
- }
- @Override
- public int hashCode() {
- int hash = 0;
- hash += (aId != null ? aId.hashCode() : 0);
- return hash;
- }
- @Override
- public boolean equals(Object object) {
- // TODO: Warning - this method won't work in the case the id fields are not set
- if (!(object instanceof Address)) {
- return false;
- }
- Address other = (Address) object;
- if ((this.aId == null && other.aId != null) || (this.aId != null && !this.aId.equals(other.aId))) {
- return false;
- }
- return true;
- }
- @Override
- public String toString() {
- return "jpaintroduction.Address[ aId=" + aId + " ]";
- }
- }
解决方法
您需要使用
@GeneratedValue注释您的id字段,以便JPA知道DB将自动生成id:
- @Id
- @Basic(optional = false)
- @Column(name = "A_ID")
- @SequenceGenerator( name = "mySeq",sequenceName = "MY_SEQ",allocationSize = 1,initialValue = 1 )
- @GeneratedValue(strategy=GenerationType.IDENTITY,generator="mySeq")
- private BigDecimal aId;
使用oracle,您可以使用GenerationType.IDENTITY和@SequenceGenerator,在这种情况下,您不需要触发器来查询序列并填充ID,JPA将为您执行此操作.我不确定GenerationType.AUTO是否可以与oracle一起使用,但如果确实如此,你需要一个触发器来查询序列并填充id. GenerationType.TABLE是最便携的解决方案,因为您使用由JPA管理的独立表来存储序列,它适用于所有数据库.
检查上面链接中的文档.