2012-06-08 64 views
0

雖然它很簡單,但我找不到任何解決方案。我使用的是playframework 1.2.3,它使用Hibernate作爲JPA。所以我認爲playframework與這個問題無關。JPA實體設計/無法刪除實體

我有一些類(I省略非相關字段)

public class User { 
    ... 
} 

public class Task { 
    public DataContainer dataContainer; 
} 

public class DataContainer { 
    public Session session; 
    public User user; 
} 

public class Session { 
    ... 
} 

所以,我有關聯從任務以DataContainer和從DataContainer到Sesssion和DataContainer屬於用戶。 DataContainers可以始終具有相同的用戶,但每個實例的會話必須不同。而且任務的DataContainer在每種情況下也都不相同。一個DataContainer可以有一個Sesesion或不(它是可選的)。我只使用單向聯想。它應該是足夠的。

換句話說:每個任務必須有一個DataContainer。每個DataContainer 必須有一個/相同的用戶和可以有一個會話。

要創建我使用JPA註釋的DB模式:

@Entity 
public class User extends Model { 
    ... 
} 

@Entity 
public class Task extends Model { 
    @OneToOne(optional = false, cascade = CascadeType.ALL) 
    public DataContainer dataContainer; 
} 

@Entity 
public class DataContainer extends Model { 
    @OneToOne(optional = true, cascade = CascadeType.ALL) 
    public Session session; 

    @ManyToOne(optional = false, cascade = CascadeType.ALL) 
    public User user; 
} 

@Entity 
public class Session extends Model { 
    ... 
} 

BTW:型號是一齣戲類,提供了主ID,只要型。

當我爲每個實體創建一個對象並'連接它們',我的意思是關聯,它工作正常。但是,當我嘗試刪除一個會話時,我得到了一個違反約束的異常,因爲DataContainer仍然引用了我想要刪除的會話。

我希望DataContainer的Session(字段)將分別設置爲null,外鍵(session_id)應該在數據庫中取消設置。這將是可以的,因爲它可選。

我不知道,我想我有多個問題。我是否使用了正確的註釋@OneToOne

我在互聯網上發現了一些額外的註釋和屬性: @JoinColumnmappedBy屬性爲反比關係。但我沒有,因爲它不是雙向的。或者是雙向關聯。本質?

另一次嘗試是使用@OnDelete(action = OnDeleteAction.CASCADE)了該限制從NO ACTION改過自新的時候更新或刪除:

ADD CONSTRAINT fk4745c17e6a46a56 FOREIGN KEY (session_id) 
     REFERENCES annotation_session (id) MATCH SIMPLE 
     ON UPDATE NO ACTION ON DELETE CASCADE; 

但在這種情況下,當我刪除一個會議上,DataContainer和用戶將被刪除。這對我來說是錯誤的。


編輯: 我使用PostgreSQL 9,JDBC的東西,包括在玩,我唯一的數據庫配置是
db=postgres://app:[email protected]:5432/app

+0

也許這個作品:加'@OneToOne DataContainer'成'Session'和修改DataContainer會話屬性'@OneToOne (的mappedBy = 「dataContainer」)'。這樣'DataContainer'類不再需要'session_id'列。 –

回答

3

您應該使用OneToOne還是ManyToOne?使用最能描述情況的關聯。如果多個DataContainer可能具有相同的會話,則它是ManyToOne。如果只有一個DataContainer可以有一個給定的會話,那麼它是一個OneToOne。

現在,如果您刪除會話,並且DataContainer仍然引用它,當然您會得到一個異常。這就是FK的用途:它確保你不能擁有一個引用一個未存在會話的DataContainer。因此,要刪除會話,您應該先更新引用它的所有數據容器。

由於您的關聯是單向的,你需要一個查詢做到這一點:

select dc from DataContainer dc where dc.session = :session 

執行這個查詢,遍歷這些結果,並設置會話爲null。然後,刪除會話。

如果協會是雙向的,你可以簡單地做:

for DataContainer dc : session.getDataContainers() { 
    dc.setSession(null); 
} 

你也可以使用一個更新查詢在一個查詢中做的一切。但要注意的是,這些更改將不會作出已載入會議DataContainers:

update DataContainer dc set dc.session = null where dc.session = :session 
+0

噢,這其實並不難。我只能用JPA註解來解決它。在刪除會話之前,我使用第一個選項並在DataContainer上設置會話爲空:我重寫Session控制器中的_delete方法,並在調用super._delete()之前執行它。 – timaschew

0

不知道,但使用什麼數據庫?是由hibernate自動加載的,還是使用自己的DDL查詢來創建它。如果是這樣,請檢查數據庫級別是否建立了約束,請驗證DataContainer表中的sessionId外鍵是否可以爲空

+0

對不起,我忘了。我使用postgresql 9 – timaschew