web-dev-qa-db-ja.com

Hibernate:insertable = false、updatable = falseは、外部キーを含む複合主キーの星座に属しますか?

Hibernateまたは他のORMで複合主キーを実装する場合、識別関係(PKの一部であるFK)を使用する複合主キーコンスタレーションでinsertable = false、updatable = falseを配置する場所は最大3つあります。

  1. 複合PKクラスの@Columnアノテーション(@Embeddableクラスのみ)または
  2. エンティティクラスの関連付け@ JoinColumn/sアノテーションまたは
  3. Into the entity class 'redundantPKプロパティの@Columnアノテーション(@IdClassクラスのみ)

3番目は@IdClassとJPA 1.0 AFAIKを使用する唯一の方法です。 http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Primary_Keys_through_OneToOne_Relationships を参照してください。ケース1と2のみを検討します。

Q:「挿入可能= false、更新可能= false」を一般的に置くのに適した場所はどれですか

この質問に関してHibernateで問題が発生しました。たとえば、Hibernate 3.5.xはZipsテーブルについて文句を言います

CREATE TABLE Zips
(
  country_code CHAR(2),
  code VARCHAR(10),
  PRIMARY KEY (country_code, code),
  FOREIGN KEY (country_code) REFERENCES Countries (iso_code)
)

で:

org.hibernate.MappingException: Repeated column in mapping for entity: com.kawoolutions.bbstats.model.Zip column: country_code (should be mapped with insert="false" update="false")
org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.Java:676)
org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.Java:698)
...

ご覧のとおり、country_code列はPKとFKの両方です。クラスは次のとおりです。

エンティティクラス:

@Entity
@Table(name = "Zips")
public class Zip implements Serializable
{
    @EmbeddedId
    private ZipId id;

    @ManyToOne
    @JoinColumn(name = "country_code", referencedColumnName = "iso_code")
    private Country country = null;
...
}

複合PKクラス:

@Embeddable
public class ZipId implements Serializable
{
    @Column(name = "country_code", insertable = false, updatable = false)
    private String countryCode;

    @Column(name = "code")
    private String code;
...
}

Insertable = false、updatable = falseをエンティティクラスの関連付けの@JoinColumnに入れると、すべての例外が消え、すべてが正常に機能します。ただし、上記のコードが機能しない理由はわかりません。 Hibernateに問題がある可能性があります。説明されているのは、@ Column "insertable = false、updatable = false"を評価していないように見えるため、Hibernateのバグですか?

本質的に、「挿入可能= false、更新可能= false」を配置する標準のJPAの方法、ベストプラクティス、または設定は何ですか?

32
Kawu

ステップごとに答えさせてください。

1. `insertable = false、updatable = false`が必要になるのはいつですか?

以下のマッピングを見てみましょう、

public class Zip {

    @ManyToOne
    @JoinColumn(name = "country_code", referencedColumnName = "iso_code")
    private Country country = null

    @Column(name = "country_code")
    private String countryCode;

}

ここでは、2つの異なるプロパティを使用して、テーブル内の同じ列を参照しています。以下のコードでは、

Zip z = new Zip();

z.setCountry(getCountry("US"));
z.setCountryCode("IN");

saveZip(z);

ここで休止状態はどうなりますか?

この種の不整合を防ぐために、hibernateはリレーションシップの更新ポイントを指定するように求めています。つまり、テーブルの同じ列をn回参照できますが、更新に使用できるのはそのうちの1つだけで、他のすべては読み取り専用ですです。

2.休止状態でマッピングに不満があるのはなぜですか?

Zipクラスでは、国コードを含む埋め込みidクラスZipIdを参照しています。上記のシナリオのように、counry_code列を2つの場所から更新する可能性があります。したがって、hibernateによって与えられるエラーは適切です。

3.あなたのケースでそれを修正するには?

いいえ。理想的には、ZipIdクラスにidを生成させたいので、ZipId内のcountryCodeにinsertable = false, updatable = falseを追加しないでください。そのため、修正は以下のようになり、countryクラスのZipマッピングを以下のように変更します。

@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code",
insertable =  false, updatable = false)
private Country country;

これがあなたの理解に役立つことを願っています。

68
ManuPK

@PrimaryKeyJoinColumn注釈を使用してこの問題を解決することもできます。 PrimaryKeyJoinColumn注釈は、別のテーブルに結合するための外部キーとして使用される主キー列を指定します。

PrimaryKeyJoinColumnアノテーションは、JOINEDマッピング戦略のエンティティサブクラスのプライマリテーブルをスーパークラスのプライマリテーブルに結合するために使用されます。 SecondaryTableアノテーション内で使用され、セカンダリテーブルをプライマリテーブルに結合します。また、参照エンティティの主キーが参照エンティティの外部キーとして使用されるOneToOneマッピングで使用される場合があります。 JOINEDマッピング戦略のサブクラスにPrimaryKeyJoinColumnアノテーションが指定されていない場合、外部キー列はスーパークラスのプライマリテーブルのプライマリキー列と同じ名前を持つと想定されます。

0
Darshan