2015-11-01 87 views
1

我正在使用JPA Eclipselink開發一個簡單的調查系統,而且我在這方面很新穎(JPA和數據庫),所以我不確定我應該採取哪種方法。如何使用JPA和實體對象生命週期

我迄今爲止所做的事情的方式是對所有數據庫邏輯使用DAO類,並且我所有的實體關係都(希望)可以正確註釋。

我的教師實體可以有多個調查,每個調查實體可以有多個問題。這就是我有關係的註解尋找:

Teacher.java

@OneToMany(mappedBy = "teacher", cascade = CascadeType.ALL) 
private List<Survey> surveys = new ArrayList<Survey>(); 

Survey.java

@ManyToOne 
@JoinColumn(name = "teacherid", referencedColumnName = "id") 
private Teacher teacher; 

@OneToMany(mappedBy = "survey", cascade = CascadeType.ALL) 
private List<Question> questions = new ArrayList<Question>(); 

Question.java

@ManyToOne 
@JoinColumn(name = "surveyid", referencedColumnName = "id") 
private Survey survey; 

在每一節課,我有一個addSometing() - 方法是這樣的: survey.addQuestion(q)

public void addQuestion(Question q) { 
    if (q != null) { 
     q.setSurvey(this); 
     questions.add(q); 
    } 
} 

然後,最後,另一個addSomething() - 方法在我的DAO,看起來像這樣每個實體:

public void addSurvey(Survey survey) { 

    EntityManager em = emf.createEntityManager(); 
    EntityTransaction tx = em.getTransaction(); 

    try { 
     tx.begin(); 
     em.persist(survey); 
     tx.commit(); 

    } catch (Exception e) { 

     e.printStackTrace(); 

     if (tx.isActive()) { 
      tx.rollback(); 
     } 

    } finally { 
     em.close(); 
    } 

} 

當我運行我的代碼,我設法創建和教師爲對象添加到數據庫就好了。然後我創建一個Question對象,並將其添加到一個新的Survey對象中,並將其添加到我的Teacher中,並且工作正常。但是,當我再嘗試堅持我的問​​題和調查對象的數據庫和合並/更新教師爲對象,我得到一個InvalidStateException:

Encountered unmanaged object "[email protected]" in life cycle state unmanaged while cascading persistence via field "no.hib.dat104.obl3.model.Question.survey" during flush. However, this field does not allow cascade persist. You cannot flush unmanaged objects or graphs that have persistent associations to unmanaged objects. 

我不認爲我在做這些事情的方式是正確的方式與JPA實體合作。任何人都可以給我一個簡短的解釋,說明我應該怎麼做,或者指向正確的方向嗎?我知道Entity Object Life Cycle,但我不確定如何在我的項目中處理此問題。

回答

0

您在addSurvey方法中獲得的EntityManager上下文是新的,因此爲空。大概在你堅持調查的時候,它有問題和一個老師分配。在您的模型中,教師實例是數據庫中的一個現有對象,並且Survey to Teacher的引用沒有級聯選項 - JPA需要在模型中遇到非託管對象時引發異常,因爲它不知道你打算如何處理它。

在你的模型中有很多方法可以解決這個問題,但它們依賴於許多其他外部因素。我能想到的最快捷的解決方案就是稍微改變一些東西,這樣老師ManyToOne的參考就是使用cascade = CascadeType.Merge選項,然後在addSurvey方法中使用em.merge(survey);。 JPA然後將確定調查和問題是新的並插入它們,同時它會將現有教師實例中的任何更改合併到數據庫中。

還有很多其他選項,例如使用擴展持久性單元,可用於閱讀教師實例以及保留您的Survey和Question實例。什麼最適合您的應用取決於您在不同情況下預期會發生什麼。

+0

我明白了。我在學校的老師告訴我爲每個HTTP會話都有一個EntityManager。我現在這樣做的方式是在有人登錄時初始化新的EM,並在他們註銷/會話過期時關閉它。這解決了我的錯誤,但是這種方法與您提出的方法相比如何? – Ferdinand

+0

這相當於我在最後提出的擴展持久性上下文 - 它的工作原理是一種常用的方法。這意味着您將所有內容保留一段時間,因爲通過EntityManager讀取的所有內容都保留在內存中,直到關閉或清除爲止。只要這沒有發生,一切都保持着管理。您仍然需要查看和處理合並您可能已經序列化或從客戶端讀回的內容。 – Chris