2014-02-25 2 views
8

JPA에 대해 배우고 데이터베이스를 만들고 일부 값을 삽입하는 작업이있었습니다. 나는 최근에 삽입 된 객체의 ID가 무엇인지 알아낼 수 있는지 궁금해했습니다. 따라서 flush 메서드 EntityManager을 사용해야합니다. JPA 작업 단위 복제본에서 Null 또는 제로 키가 발생했습니다

불행히도 나는 위의 방법을 사용하면 작업 클론의 단위

예외가 발생한

제로 기본 키를 얻었다. 문제는 내 데이터베이스가 모두 ID's 자동 증가 (나는 오라클 11G 익스프레스)를 사용하므로, 커밋하기 전에 null 값을 가지며 트랜잭션을 롤백한다고 가정합니다.

문제를 해결하려면 어떻게해야합니까?

은 (ID 년대는 [오라클의 시퀀스 및 트리거] 자동 증가하고 있습니다) DB 수 있습니다 :

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(); 
    } 
} 

주소 클래스 당신은 당신의 주석을 필요

@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 + " ]"; 
    } 

} 
+0

후 내가 질문을 업데이트 CamiloBermúdez @ Address' – Camilo

+0

'에 대한 코드입니다. – ashur

답변

4

id 필드를 @GeneratedValue으로 변경하여 JPA가 그 당신이 ID를 순서를 쿼리하고 채우는 트리거를 필요로하지 않는 경우에 GenerationType.IDENTITY@SequenceGenerator을 사용할 수 있습니다 오라클과

@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; 

는, JPA는 당신을 위해 그것을 할 것입니다 : 전자 DB가 자동으로 ID를 생성합니다. 나는 GenerationType.AUTO이 oracle과 함께 작동하는지 확신하지 못하지만 만약 그렇다면 시퀀스를 쿼리하고 id를 채울 트리거가 필요합니다. GenerationType.TABLE은 JPA에서 관리하는 독립 테이블을 사용하여 시퀀스를 저장하므로 모든 데이터베이스에서 작동하므로 가장 이식 가능한 솔루션입니다.

위의 링크에서 문서를 확인하십시오.

+0

'@GeneratedValue (strategy = GenerationType.IDENTITY, generator = "SEQ_ADDRESS")','SEQUENCE','AUTO' 등의 다른 모든 조합을 예외를 던져 넣어야했습니다. 나는 그것이 올바르게 작동하고 있는지 또는 단지 사고인지 확실하지 않습니다. 'AUTO'의 경우'SEQUENCE'에 대해'table or view does not exist'를 던집니다. - [SEQ_ADDRESS]라는 이름의 순서가 잘못 설정되었습니다. 그 증분은 할당 전 크기와 일치하지 않습니다.'제발 설명해 주시겠습니까?: P – ashur

+1

확실하고, 그냥 다시 편집하십시오. 더 많은 정보가 필요하면 여기에 관한 많은 문서가 있습니다. 행운을 빕니다. – Camilo

15

수동으로 데이터베이스에 ID가 0 (제로) 인 항목을 추가했기 때문에이 문제가 발생했습니다. 제 경우 EclipseLink는 "0"으로 ID를 처리 할 수 ​​없습니다. 그래서 나는 나의의 persistence.xml에 다음을 추가 :

 <property name="eclipselink.allow-zero-id" value="true"/> 

이 속성은 EclipseLink가 유효한 ID로 제로를 처리하기 위해 말한다.

[1] http://meetrohan.blogspot.de/2011/11/eclipselink-null-primary-key.html

+2

감사합니다. 이것은 제가 찾고 있던 정확한 해결책입니다. 나는 @Camilo Bermudez가 제안한 (GeneratedValue annotation) 것을 알았지 만 ID = 0 인 내 DB에 사용자를 추가 한 후에이 오류가 발생하기 시작했습니다. – rbaleksandar

+0

* SEQUENCE *를 사용할 때 이런 일이 생겼습니다. [Oracle] (https://docs.oracle.com/cd/B12037_01/server.101/b10759/statements_6014.htm)은 1로 시작하지만 [HSQLDB] (http://www.hsqldb.org/doc/guide) /ch09.html#create_sequence-section)은 0으로 시작합니다. – SebastianH

관련 문제