7

目標:ImportJobにimportJobIdを割り当てテーブルのIDの外部キーとして使用したいので、importJobIdがある場合は、Jobがないと割り当てができないため、割り当てにidを含めることができます。

ImportJobテーブルには[ORGID、IMPORTJOBTYPE]として複合主キーがあり、Hibernateで外部キー関係を作成しようとしています。

  <id name="id"
        column="ID">
        <generator class="native"/>
    </id>
    <many-to-one name="importjobid"
                 class="com.delta.pdo.admin.ImportJob"
                 cascade="save-update"/>

Allocation.hbm.xmlで、機能せず、次のようなエラーメッセージが表示されます。

Foreign key (FKB29B5F7366007086:ALLOCATIONS [importjobid])) 
must have same number of columns as the 
referenced primary key (IMPORTJOBMANAGMENT [ORGID,IMPORTJOBTYPE])

これが私のImportJob.hbm.xmlファイルです

    <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.delta.pdo.admin.ImportJob" table="IMPORTJOB" lazy="false">
        <!-- we don't cache this since the commissions code is too screwed up to work with -->
        <composite-id>
            <key-property name="orgId" type="long" column="ORGID"/>
            <key-property name="importJobType" type="java.lang.String" column="IMPORTJOBTYPE"/>
        </composite-id>

        <!-- Make sure importjobid is not-null='true '-->
        <property name="importjobid" type="long" column="IMPORTJOBID" />
        <property name="allocations" type="boolean" column="ALLOCATIONS" />
    </class>
</hibernate-mapping>

参照用のBeanクラスは次のとおりです。

public class AllocationBean extends WorkbenchBeanBase
{
    private static final Logger log = Logger.getLogger(AllocationBean.class);
    private Float allocations;
    private String importJobType;
    private long id;
    private long orgId;
}

public class ImportJobManagment implements Serializable
{
    private long importjobid;
    private long orgId;
    private String importJobType;
    private boolean allocations = false;
}

getter/setter簡単にするために削除しました。

更新:1 現在の設定方法では、orgIdとimportJobTypeの複合キーへの外部キー参照を持つ1つのテーブルにid列がありますが、これが可能かどうかわからず、別の複合キーに外部キーされた単一の列がありますテーブルですが、それが私のユースケースです。

更新:2

すばらしい詳細に感謝します。これにより、外部キーの実装に関する知識が確実に向上しますが、最終的な目標は、2つのテーブル間の1対1のマッピングです。ここで、テーブルAには、そのテーブルとテーブルBの一意の行を識別するための複合キーがあります。テーブルAへの外部キー参照を持つ主キーがあり、テーブルAにエントリがある場合、同じjobIdエントリがテーブルBにあるはずです。ここで、テーブルBに単一列の主キーを参照することはできないという点がわかります。表Aの複合キー。

したがって、基本的に、テーブルAに複合主キーがあり、テーブルBに休止状態を使用する単一列の主キーがあるテーブル間で1対1のマッピングが必要です。これはもちろん上記のエラーが発生するため、テーブルに複合キーを作成します。 Bもまた、テーブルAへの外部キー参照を作成します。詳細な入力に感謝します。後で、調査結果を使用して質問を検証および更新します。

4

2 に答える 2

14

エラーはそれ自体を物語っています。複合主キーを参照するには、複合外部キーが必要です。(複合主キーは、キーを作成するために2つのフィールドの一意の組み合わせが必要であると述べています。その場合、1つの列だけで一意のキーを参照することはできません。)

xmlマッピングファイルを使用してこれをどのように実現するかについてはよくわかりませんが、最近ではほとんどの人が注釈を使用しています。

Javaクラスに関しては、ImportJobManagementがImportJobを保持していると想定しているため、クラスはIDを参照するのではなく、オブジェクト自体を次のように参照する必要があります。

public class ImportJobManagment implements Serializable {
    private ImportJob importJob;
    ...
}

Javaクラスは、複合キーのメンバーではなく、他のクラスを参照する必要があります。複合キーからJavaメンバー変数にマップするのはマッピング次第です。

更新への回答:

簡単な答えはノーです、あなたはできません。外部キーの仕組みにより、テーブル内の特定の行を参照できます。また、特定の行を確実に参照するには、IDが必要です。これは、1つの行のみを記述し、他の行は記述しないものです。SQLには、これを実現するための構造、つまり一意キーがあります。列(または列の複合)が一意であると述べることにより、その/それらの結合された値が一意であり、この値を持つテーブル全体に最大1つの行があり、それ以外は制約違反になることがわかります。 。

したがって、外部キーは、単一の一意性制約付き列、または複数の列にまたがる複合一意性キーのいずれかを指します。すべてのテーブルにはすでに一意のキーである主キー(常に一意)があるため、これを外部キーの参照に使用するのが一般的ですが、任意のunqiue列が機能します。

最も簡単なケースは、単一列の一意キーを使用してテーブルを参照する場合です。単一の列「id」を保持する2つの単純なテーブルAと「id」列を保持するBだけでなく、Aの「id」列への外部キーを持つ別の列a_idもあります。このインスタンス状況はこれである可能性があります:

A:
| id | 
|----|
|  1 |
|  2 |
|  3 |

B:
| id | a_id |
| 2  |  3   |
| 3  |  1   |

ここで、Bの各行はAの行を参照します。その直接参照であるテーブルBのa_idの値は、A''id'列の値に直接対応します。したがって、ID2のBはID3のAを参照します。

次に、複合一意キーを使用してテーブルを参照する方法を見てみましょう。例を続けましょう。ただし、Aには別の列「sec_id」があり、「id」と一緒に複合主キーを構成します。

A:
| id | sec_id |
|----|--------|
| 1  |   3    |
| 3  |   1    |
| 3  |   7    |

B:
| id | a_id |
|----|------|
| 2  |  3   |

この状況では、Bに問題があります。外部キーは、その参照元のテーブル内の1つの行を参照する必要があるため、これは明らかに機能しません。値「3」はAのどの行を表しますか?最初の行のsec_id?2番目または3番目のID(ただし、その場合はどちらですか?)?もちろん、答えはどちらでもありません。Bには、Aの単一の行を参照するのに十分な情報がないため、SQLにはそれがありません。したがって、そのような外部キーを追加することは許可されていません。

BがAを参照するには、Aの'id'列とAの'sec_id'列の両方への参照が必要です。これは、Aの単一の行が('id'、'sec_id'の一意の組み合わせによって識別されるためです。 )ペア。したがって、Bは次のようになります。

| id | a_id | a_sec_id |
|----|------|----------|
| 1  |  1   |     3    |
| 2  |  3   |     1    |
| 3  |  3   |     7    |

これで、BはAの単一の行を参照するのに十分な情報を保持し、データが示すように、それは保持します。

再度更新:

私は現在JPA認定を読んでおり、複合キーマッピングの章に到達しました。複合主キーをマップするには、キーの属性をマップする主キークラスが必要です。これを行うには2つの方法があります。1つはエンティティ自体にもキー属性をマップする必要がある方法、もう1つは埋め込みキーとして使用する方法です。

私はコード例を提供します、彼らはかなり彼ら自身のために話します(それは注釈を使用しています、あなたは本当にそれもするべきです)。

最初の例は、通常のidクラス(埋め込まれていない)を使用した基本例です。ここでは、主キーが整数IDと国で構成されているEmployeeエンティティがあります(異なる国にいる場合、2人の従業員が同じIDを持つことができます)。

@Entity
@IdClass(EmployeeId.class)
public class Employee {
    @Id private String country
    @Id
    @Column(name = "EMP_ID")
    private int id;
    private String name;
    ...
}

public class EmployeeId implements Serializable {
    private String country;
    private int id;

    public EmployeeId() { }
    public EmployeeId(final String country, final int id) {
        this.country = country;
        this.id = id;
    }

    //getters for the properties

    public boolean equals(final Object other) {
    //must be implemented
    }

    public int hashCode() {
    //must be implemented
    }
}

ノート:

  • @IdClass-クラスのアノテーション。
  • idクラスの両方の属性もエンティティで定義する必要があります
  • idクラスはequalsとハッシュコードを実装する必要があります

これを行うもう1つの方法は、埋め込まれたidクラスを使用することです。

@Entity
public class Employee {
    @EmbeddedId
    private EmployeeId id;
    private String name;

    public Employee(final String country, final int id) {
        this.id = new EmployeeId(country, id);
    }

    public String getCountry() {
        return id.getCountry();
    }
}   

@Embeddable
public class EmployeeId {
   private String country;
   @Column(name = "EMP_ID")
   private int id;

   //constructor + getters + equals +hashCode
}

ノート:

  • エンティティでid属性を定義する必要はありません
  • エンティティからid-classの属性を取得するには、id-classからそれらを取得する必要があります

後者の方がコンパクトで重複がないので気に入っていますが、この2つをどのように使用するかはわかりません。

于 2013-01-24T22:36:07.033 に答える
-1

ImportJob.hbm.xml

insert = falseこれを使用して、次のようにimportjobidに追加します。

<property name="importjobid" type="long" 
    column="importjobid" type="long" insert="false"/>
于 2013-11-27T04:35:22.370 に答える