48

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

私が直面している問題は、FK が複合 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>

このコードは、名前を持つ Company の SELECT および INSERT に対して問題なく機能します。既存のレコードを更新しようとしたときに問題が発生しました。BatchUpdateException を受け取り、SQL ログを調べたところ、Hibernate が愚かなことをしようとしていることがわかりました...

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要素に変更しようとしましたが、それもうまくいきませんでした。そう...

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

4

2 に答える 2

104

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

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

于 2011-02-18T14:24:53.350 に答える
0

"Dino TW" has provided the link to the comment Hibernate Mapping Exception : Repeated column in mapping for entity which has the vital information.

The link hints to provide "inverse=true" in the set mapping, I tried it and it actually works. It is such a rare situation wherein a Set and Composite key come together. Make inverse=true, we leave the insert & update of the table with Composite key to be taken care by itself.

Below can be the required mapping,

<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>
于 2016-11-21T13:59:41.760 に答える