web-dev-qa-db-ja.com

1対多のFKでも使用される複合IDキープロパティに「insert = 'false' update = 'false'」をマッピングするにはどうすればよいですか?

私は、既存のDBスキーマを使用したレガシーコードベースに取り組んでいます。既存のコードは、SQLおよびPL/SQLを使用してDBでクエリを実行します。プロジェクトのデータベースエンジンにとらわれない一部(最初は、すべてを最終的に変更する)を作成するという任務を負っています。 Hibernate 3.3.2.GAおよび "* .hbm.xml"マッピングファイル(注釈ではなく)の使用を選択しました。残念ながら、既存のスキーマを変更することはできません。これは、レガシー機能を後退させることができないためです。

私が直面している問題は、FKがalso複合PKの一部である、一方向の1対多の関係をマップしようとしているときです。クラスとマッピングファイルは次のとおりです...

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が何かをしようとしているのを見ましたstupid...

update COMPANY_NAME set COMPANY_ID=null where COMPANY_ID=?

Hibernateは、子レコードを更新する前に関連付けを解除しようとしました。問題は、このフィールドがPKの一部であり、null不可であることです。 Hibernateがこれを行わないようにするための簡単な解決策は、親マッピングの「key」要素に「not-null = 'true'」を追加することです。 SOこれでマッピングは次のようになります...

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でサポートされていないことです。また、キーを多対一の要素に変更しようとしましたが、それも機能しませんでした。そう...

1対多のFKでも使用される複合IDキープロパティに「insert = 'false' update = 'false'」をマッピングするにはどうすればよいですか?

40
Jesse Webb

あなたが探している注釈は次のとおりだと思います:

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

そして、ここに示すように(23.4.2で)hbm.xmlで同様のマッピングを使用できるはずです。

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

84
mcyalcin

「Dino TW」はコメントへのリンクを提供しました Hibernate Mapping Exception:エンティティのマッピングで繰り返し列 これは重要な情報を持っています。

リンクは、セットマッピングで「inverse = true」を提供することを示唆しています。私はそれを試してみましたが、実際に機能します。 SetキーとCompositeキーが一緒になるようなまれな状況です。 inverse = trueに設定すると、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>