2016-02-13 82 views
0

我有一個包含一個@Lob以下嵌入類:爲什麼EclipseLink通過@ElementCollection支持@CascadeOnDelete?

@Embeddable 
public class EntityState { 

    private Integer version; 
    @Lob 
    @XmlJavaTypeAdapter(CharArrayAdapter.class) 
    private char[] xmlState; 
    ... 
} 

我也有包含上述嵌入以下嵌入類:

@Embeddable 
public class EntityEvent { 

    @NotNull 
    private String note; 

    private EntityState entityState; 

    ... 
} 

最後,我有一個包含許多實體類名爲歷史的屬性是EntityEvents的列表。下面是一個例子:

@Entity 
public class Company { 

    @NotNull 
    @ElementCollection 
    private List<EntityEvent> history; 

    ... 
} 

當我在GlassFish中4.1部署我的應用程序,創建的EclipseLink在我德比10.11.1.1數據庫下表:

  • 公司
  • COMPANY_HISTORY

當我創建一個新公司時,我的應用程序創建一個EntityEvent並將EntityEvent添加到公司歷史記錄。

當我修改公司,我的應用程序執行以下操作:

  • 創建一個EntityState對象,並將xmlState屬性未修改實體的XML表示。
  • 創建包含上述EntityState的EntityEvent對象。
  • 將EntityEvent添加到公司歷史記錄。

的問題是,當我嘗試刪除具有多個EntityEvents我收到以下錯誤歷史的實體:

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLSyntaxErrorException: Comparisons between 'CLOB (UCS_BASIC)' and 'CLOB (UCS_BASIC)' are not supported. Types must be comparable. String types must also have matching collation. If collation does not match, a possible solution is to cast operands to force them to the default collation (e.g. SELECT tablename FROM sys.systables WHERE CAST(tablename AS VARCHAR(128)) = 'T1')

Error Code: 20000 Call: DELETE FROM Company_HISTORY WHERE ((((((((((CHANGES = ?) AND (CLIENTTYPE = ?)) AND (CREATED = ?)) AND (IPADDRESS = ?)) AND (NOTE = ?)) AND (TYPE = ?)) AND (VERSION = ?)) AND (XMLSTATE = ?)) AND (CREATER_ID = ?)) AND (Company_ID = ?)) bind => [10 parameters bound]

我發現下面的鏈接問題談幾點參考:

我嘗試了上面引用的stackoverflow文章中描述的@OrderColumn技術,但是這在EclipseLink中不起作用。

,對我的工作是對的EclipseLink非標準@CascadeOnDelete註釋添加到我的實體,如下所示的解決方案:

@Entity 
public class Company { 

    @NotNull 
    @ElementCollection 
    @CascadeOnDelete 
    private List<EntityEvent> history; 

    ... 
} 

執行這一變化,並重建我的數據庫後,我COMPANY_HISTORY表中有一個新的定義:

  • 沒有@CascadeOnDelete
    • ALTER TABLE COMPANY_HISTORY添加約束CMPNYHISTORYCMPNYD FO REIGN KEY(COMPANY_ID)參考公司(ID);
  • 隨着@CascadeOnDelete
    • ALTER TABLE COMPANY_HISTORY添加約束CMPNYHISTORYCMPNYD外鍵(COMPANY_ID)參考COMPANY(ID)ON DELETE CASCADE;

解決我的問題,讓我感到驚訝,因爲它似乎重複。我的理解是JPA應刪除實體時與實體關聯的所有可嵌入對象。是的EclipseLink有作爲記錄在以下鏈接這個非標準的註釋這一事實使我認爲的EclipseLink有缺陷,而不是固定的錯誤創造了一個新的@CascadeOnDelete註釋,這樣的bug將由數據庫級聯刪除功能被掩蓋。

所以我的問題是爲什麼。爲什麼EclipseLink通過@ElementCollection支持@CascadeOnDelete?

回答

1

CascadeOnDelete是一個簡單的功能,指定你所指定的「關於級聯刪除」選項,在你的表格,讓JPA不需要發出SQL刪除相應的引用。這個SQL可以應用於任何引用,這就是CascadeOnDelete處理元素集合映射和任何其他參考映射的原因。

您的問題與數據庫中lob比較限制有關,並且由於沒有用於唯一標識元素集合行的ID字段,因此此限制會干擾EclipseLink嘗試確保僅刪除所需行的方式。如果您願意在您的表格中添加訂單欄,爲什麼不直接將EntityEvent設置爲實體?或描述here,以便它使用外鍵和排序依據字段或作爲主鍵來唯一地標識,而不是包括LOB字段行字段的任意組合,你可以自定義的EclipseLink。

+0

@CascadeOnDelete似乎是我的問題的完美解決方案,因爲它提供了所有的鏈接embeddables從COMPANY_HISTORY表中刪除時,本公司實體被刪除的環境,並減少了執行此任務所需的SQL。然而,我很困惑,爲什麼這是必要的。當實體被刪除時,必須刪除嵌入。爲什麼當公司實體被刪除時,EclipseLink不會簡單地發送「刪除COMPANY_HISTORY,其中company_id = <被刪除公司的ID>」命令?爲什麼它比較所有的領域?感謝您的幫助! –