2013-04-05 132 views
0

,我只是工作在@EmbededId代碼,我想要的實體堅持之前做一個自動遞增,這是希望在不使用@GeneratedValue和標識列做,重用持久化上下文在JPA

下面

是複合的ID表,

create table TBL_EMPLOYEE_002(
    ID integer, 
    COUNTRY varchar(50), 
    NAME varchar(50), 
    constraint PK_EMP_00240 primary key(ID,COUNTRY) 
) 

這是實體映射的代碼,

@Entity 
@Table(name="TBL_EMPLOYEE_002") 
public class EmployeeEntitySix implements Serializable{ 

// contructor's 

    @EmbeddedId  
    private EmployeeIdTwo id; 

    @Column(name="NAME") 
    private String employeeName; 

// getters and setter's 

    @PrePersist 
    public void incId(){ 
     EntityManager em = null; 
     Query q = null; 
     EntityManagerFactory emf = null; 
     try{ 
      emf = Persistence.createEntityManagerFactory("forPractise"); 
      em = emf.createEntityManager(); 
      q = em.createQuery("select max(e.id.employeeId) from EmployeeEntitySix e"); 
      List list = q.getResultList(); 
      Integer i = (list != null && list.size() > 0) ? Integer.valueOf(list.get(0).toString()) : 0; 
      this.getId().setEmployeeId(++i); 
     }catch(Exception e){ 
      System.out.println("EXCETION WHILE INCREASING COUNTER..."); 
      e.printStackTrace(); 
     }finally{ 
      if(em != null && em.isOpen()){ 
       em.close(); 
      } 
      if(getEmf() != null && getEmf().isOpen()){ 
       getEmf().close(); 
      } 
     } 


} 

這是複合ID映射,

@Embeddable 
public class EmployeeIdTwo implements Serializable{ 


    @Column(name="ID") 
    private Integer employeeId; 

    @Column(name="COUNTRY",length=50) 
    private String empCountry; 

// getters and setters 

    } 

這個代碼是我的主要方法,這種方法主要是在一些其他類,

public static void main(String [] args){ 
    EntityManagerFactory emf = null; 
    EntityManager em = null; 
    EntityTransaction tx = null; 
    try{ 
     emf = Persistence.createEntityManagerFactory("forPractise"); 
     em = emf.createEntityManager(); 
     tx = em.getTransaction();    
     tx.begin(); 
    EmployeeEntitySix employee = new EmployeeEntitySix(new EmployeeIdTwo("ZIMBABWE"), "Henry Olanga"); 
    em.persist(employee); 
.... 
} 

現在上面的代碼運行正常, 每當我堅持實體「EmployeeEntitySix」,該法註解使用@PerPersist運行,它將首先獲取最大id,將其增加,將其設置爲嵌入實體中的id並保留該實體。

現在的問題是,

我創建EntityManagerFactory的兩倍, 首先在主要方法,在實體EmployeeEntitySix的@PrePersist方法 第二次。因此,無論我是否可以使用實體EmployeeEntitySix中的main方法中創建的第一個Entitymanagerfactory,同時預留,還是我可以重複使用實體中的@PrePersist方法中main方法中第一次創建的entitymanager。

僅供參考,我使用純java環境,我沒有使用Java EE容器。

+0

您沒有顯示getEMF()的功能,但是如果它是靜態的,在持續回調中關閉EMF並且提供程序正在使用時可能不是個好主意它 – Chris 2013-04-05 11:29:12

+0

但我的問題是,我將如何重用EmtityManager,我已經在主要方法中創建,在@PrePersist方法 – 2013-04-05 11:32:09

回答

1

默認情況下,Hibernate會嘗試保留實體類或嵌入ID的所有字段,包括字段emf,但它不知道如何保留類型爲EntityManagerFactory的字段。

當然,堅持EntityManagerFactory是沒有意義的。您可以將該字段標記爲@Transient以防止它被持續存在,但是您只會遇到不同的問題。

使用@PersistenceUnit註釋注入EntityManagerFactory僅適用於在符合Java EE的應用程序服務器上運行的應用程序中的CDI Beans和EJB。當你使用主要方法時,我假設你的例子是一個簡單的JSE程序。

此外,您不應該在生命週期回調方法(如@PrePersist)中訪問EntityManager。從JPA規範(JSR 317: JavaTM Persistence API, Version 2.0)引述:

一般而言,便攜式應用的生命週期方法不應以EntityManager的 或查詢操作,訪問其他實體實例,或修改 相同持久上下文內的關係。生命週期回調方法可能會修改調用它的實體的非關係狀態 。

我建議你保持EntityManagerFactory出你的嵌入式id類,也擺脫了incId -Method。相反,您可以在調用persist之前執行查詢以確定主方法中的新employeeId。只要程序只有一個實例可以與數據庫一起工作,就可以正常工作。當有多個程序嘗試插入新員工時,可能會出現兩個程序嘗試插入相同ID的競爭條件。

爲了防止出現這種情況,您可以使用數據庫序列生成employeeId,其註釋爲@GeneratedValue@SequenceGenerator。您可以在此處找到有關身份證生成的更多信息:http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Sequencing

+0

我編輯了我的問題,在這裏我已經將PrePersist的代碼移動到實體EmployeeEntitySix,我的問題是如何可以我重用在主方法中創建的EntityManager,實體的PrePersist方法EmployeeEntitySix – 2013-04-05 12:20:23

+0

唯一能做到這一點的方法是使用EntityManager的公共靜態變量,但我強烈反對這一點,對於各種原因之一,就是上面提到的JPA規範的引用。 – 2013-04-08 10:18:46