为什么EclipseLink使用@ElementCollection支持@CascadeOnDelete?

时间:2016-02-13 13:23:35

标签: jpa eclipselink cascade

我有以下包含@Lob的可嵌入类:

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

    ...
}

最后,我有许多实体类,它们包含一个名为history的属性,它是一个EntityEvents列表。以下是一个例子:

@Entity
public class Company {

    @NotNull
    @ElementCollection
    private List<EntityEvent> history;

    ...
}

当我在GlassFish 4.1中部署我的应用程序时,EclipseLink在我的Derby 10.11.1.1数据库中创建以下表:

  • COMPANY
  • COMPANY_HISTORY

当我创建新公司时,我的应用程序会创建一个EntityEvent并将EntityEvent添加到公司历史记录中。

当我修改公司时,我的申请会执行以下操作:

  • 创建一个EntityState对象,并将xmlState属性设置为未修改实体的XML表示形式。
  • 创建包含上述EntityState的EntityEvent对象。
  • 将EntityEvent添加到公司历史记录中。

问题是当我尝试删除具有多个EntityEvents的历史记录的实体时,我收到以下错误:

  

异常[EclipseLink-4002](Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd):org.eclipse.persistence.exceptions.DatabaseException内部异常:java.sql.SQLSyntaxErrorException:&#39; CLOB之间的比较(UCS_BASIC) )&#39;和&#39; CLOB(UCS_BASIC)&#39;不受支持。类型必须具有可比性。字符串类型还必须具有匹配的排序规则。如果排序规则不匹配,可能的解决方案是转换操作数以强制它们进行默认排序规则(例如SELECT tablename FROM sys.systables WHERE CAST(tablename AS VARCHAR(128))=&#39; T1&#39;)

     

错误代码:20000调用:DELETE FROM Company_HISTORY WHERE(((((((((((CHANGES =?)AND(CLIENTTYPE =?))AND(CREATED =?))AND(IPADDRESS =?))AND(注意=?))AND(TYPE =?))AND(VERSION =?))AND(XMLSTATE =?))AND(CREATER_ID =?))AND(Company_ID =?))bind =&gt; [10个参数绑定]

我在以下链接中找到了一些对此问题的引用:

我尝试了上面引用的stackoverflow文章中描述的@OrderColumn技术,但这在EclipseLink中不起作用。

对我有用的解决方案是将EclipseLink非标准@CascadeOnDelete注释添加到我的实体,如下所示:

@Entity
public class Company {

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

    ...
}

执行此更改并重建我的数据库后,我的COMPANY_HISTORY表有一个新定义:

  • 没有@CascadeOnDelete
    • ALTER TABLE COMPANY_HISTORY ADD CONSTRAINT CMPNYHISTORYCMPNYD FOREIGN KEY(COMPANY_ID)REFERENCES COMPANY(ID);
  • 使用@CascadeOnDelete
    • ALTER TABLE COMPANY_HISTORY ADD CONSTRAINT CMPNYHISTORYCMPNYD FOREIGN KEY(COMPANY_ID)REFERENCES COMPANY(ID) ON DELETE CASCADE ;

我的问题的解决方案让我感到惊讶,因为它看起来很重复。我的理解是,当删除实体时,JPA应删除与实体关联的所有可嵌入项。 EclipseLink具有以下链接中记录的非标准注释这一事实使我认为EclipseLink有一个错误,而不是修复错误创建一个新的@CascadeOnDelete注释,以便错误将被数据库级联删除功能所掩盖。

所以我的问题是为什么。为什么EclipseLink使用@ElementCollection支持@CascadeOnDelete?

1 个答案:

答案 0 :(得分:1)

CascadeOnDelete只是一个功能,它指定您已指定&#34; On删除级联&#34;表中的选项,以便JPA不需要发出SQL来删除相应的引用。此SQL可以应用于任何引用,这就是CascadeOnDelete处理元素集合映射和任何其他引用映射的原因。

您的问题与数据库中的lob比较限制有关,并且由于没有唯一标识元素集合行的ID字段,因此此限制会干扰EclipseLink尝试确保仅删除所需的方式行。如果您愿意在表中添加订单列,为什么不将EntityEvent作为实体?或者您可以按照here所述自定义EclipseLink,以便它使用外键和orderBy字段或任何字段组合作为主键来唯一标识行而不是包含lob字段。