如何在复合id键属性上映射“insert ='false'update ='false'”,该属性也用于一对多FK?

时间:2011-02-03 23:23:30

标签: hibernate-mapping hbm hibernate-onetomany hbmxml

我正在使用现有数据库架构的遗留代码库。现有代码使用SQL和PL / SQL在DB上执行查询。我们的任务是使项目数据库引擎不可知的一小部分(最初,最终改变一切)。我们选择使用 Hibernate 3.3.2.GA 和“* .hbm.xml”映射文件(而不是注释)。遗憾的是,改变现有模式是不可行的,因为我们无法回归任何遗留功能。

我遇到的问题是当我试图映射单向一对多关系时,其中FK 也是复合PK的一部分。这是类和映射文件......

CompanyEntity.java

public class CompanyEntity {
    private Integer id;
    private Set<CompanyNameEntity> names;
    ...
}

CompanyNameEntity.java

public class CompanyNameEntity implements Serializable {
    private Integer id;
    private String languageId;
    private String name;
    ...
}

CompanyNameEntity.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.example">

    <class name="com.example.CompanyEntity" table="COMPANY">
        <id name="id" column="COMPANY_ID"/>
        <set name="names" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
            <key column="COMPANY_ID"/>
            <one-to-many entity-name="vendorName"/>
        </set>
    </class>

    <class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
        <composite-id>
            <key-property name="id" column="COMPANY_ID"/>
            <key-property name="languageId" column="LANGUAGE_ID"/>
        </composite-id>
        <property name="name" column="NAME" length="255"/>
    </class>

</hibernate-mapping>

此代码适用于具有名称的公司的SELECT和INSERT。我尝试更新和现有记录时遇到了问题。我收到了一个BatchUpdateException,在查看了SQL日志之后,我看到Hibernate试图做一些事情愚蠢的 ......

update COMPANY_NAME set COMPANY_ID=null where COMPANY_ID=?

Hibernate在更新之前试图将子记录关联起来。问题是这个字段是PK的一部分而不是可空的。我发现快速解决方案使Hibernate不这样做是为了将“not-null ='true'”添加到父映射中的“key”元素。现在可能映射看起来像这样......

CompanyNameEntity.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.example">

    <class name="com.example.CompanyEntity" table="COMPANY">
        <id name="id" column="COMPANY_ID"/>
        <set name="names" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
            <key column="COMPANY_ID" not-null="true"/>
            <one-to-many entity-name="vendorName"/>
        </set>
    </class>

    <class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
        <composite-id>
            <key-property name="id" column="COMPANY_ID"/>
            <key-property name="languageId" column="LANGUAGE_ID"/>
        </composite-id>
        <property name="name" column="NAME" length="255"/>
    </class>

</hibernate-mapping>

此映射提供异常......

org.hibernate.MappingException: Repeated column in mapping for entity: companyName column: COMPANY_ID (should be mapped with insert="false" update="false")

我现在的问题是我尝试将这些属性添加到key-property元素,但DTD不支持。我也尝试将它改为一个多对一的关键元素,但这也不起作用。所以......

如何在复合id键属性上映射“insert ='false'update ='false'”,该属性也用于一对多FK?

2 个答案:

答案 0 :(得分:83)

我认为您正在寻找的注释是:

public class CompanyName implements Serializable {
//...
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID", insertable = false, updatable = false)
private Company company;

你应该能够在hbm.xml中使用类似的映射,如下所示(在23.4.2中):

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/example-mappings.html

答案 1 :(得分:0)

“Dino TW”提供了评论Hibernate Mapping Exception : Repeated column in mapping for entity的链接,其中包含重要信息。

链接提示在集合映射中提供“inverse = true”,我尝试了它并且它实际上有效。这是一种罕见的情况,其中Set和Composite键组合在一起。使inverse = true,我们留下插入&amp;使用Composite键更新表格,以便自行处理。

下面可以是必需的映射,

<class name="com.example.CompanyEntity" table="COMPANY">
    <id name="id" column="COMPANY_ID"/>
    <set name="names" inverse="true" table="COMPANY_NAME" cascade="all-delete-orphan" fetch="join" batch-size="1" lazy="false">
        <key column="COMPANY_ID" not-null="true"/>
        <one-to-many entity-name="vendorName"/>
    </set>
</class>