36

私は(春に)注釈付きのHibernateを使用しており、順序付けられた多対1の関係を持つオブジェクトがあります。このオブジェクトは、複合主キーを持つ子オブジェクトであり、その1つのコンポーネントは外部キーに戻ります。親オブジェクトのID。

構造は次のようになります。

+=============+                 +================+
| ParentObj   |                 | ObjectChild    |
+-------------+ 1          0..* +----------------+
| id (pk)     |-----------------| parentId       |
| ...         |                 | name           |
+=============+                 | pos            |
                                | ...            |
                                +================+

注釈のさまざまな組み合わせを試しましたが、どれも機能していないようです。これは私が思いついた最も近いものです:

@Entity
public class ParentObject {
    @Column(nullable=false, updatable=false)
    @Id @GeneratedValue(generator="...")
    private String id;

    @OneToMany(mappedBy="parent", fetch=FetchType.EAGER, cascade={CascadeType.ALL})
    @IndexColumn(name = "pos", base=0)
    private List<ObjectChild> attrs;

    ...
}

@Entity
public class ChildObject {
    @Embeddable
    public static class Pk implements Serializable {
        @Column(nullable=false, updatable=false)
        private String parentId;

        @Column(nullable=false, updatable=false)
        private String name;

        @Column(nullable=false, updatable=false)
        private int pos;

        @Override
        public String toString() {
            return new Formatter().format("%s.%s[%d]", parentId, name, pos).toString();
        }

        ...
    }

    @EmbeddedId
    private Pk pk;

    @ManyToOne
    @JoinColumn(name="parentId")
    private ParentObject parent;

    ...
}

私は長い実験の末にこれに到達しました。そこでは、他のほとんどの試みで、さまざまな理由で休止状態にさえロードできないエンティティが生成されました。

更新:コメントをありがとう。私はいくつかの進歩を遂げました。私はいくつかの調整を行いましたが、より近いと思います(上記のコードを更新しました)。ただし、現在、問題は挿入にあります。親オブジェクトは正常に保存されているように見えますが、子オブジェクトは保存されていません。私が判断できたのは、休止状態が子オブジェクトの(複合)主キーのparentId部分を埋めていないためです。 m一意ではないエラーが発生する:

org.hibernate.NonUniqueObjectException:
   a different object with the same identifier value was already associated 
   with the session: [org.kpruden.ObjectChild#null.attr1[0]]

自分のコードに属性namepos属性を入力していますが、親IDはまだ保存されていないため、もちろんわかりません。これを記入するように休止状態を説得する方法についてのアイデアはありますか?

ありがとう!

4

9 に答える 9

20

Manningの本「JavaPersistencewithHibernate」は、セクション7.2でこれを行う方法の概要を示す例があります。幸い、この本を所有していない場合でも、JPAバージョンのCaveat Emptorサンプルプロジェクト(ここに直接リンク)をダウンロードし、クラスCategoryとパッケージを調べることで、このソースコードの例を見ることができます。CategorizedItemauction.model

また、以下に主要な注釈を要約します。それでも問題がない場合はお知らせください。

ParentObject:

@Entity
public class ParentObject {
   @Id @GeneratedValue
   @Column(name = "parentId", nullable=false, updatable=false)
   private Long id;

   @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
   @IndexColumn(name = "pos", base=0)
   private List<ChildObject> attrs;

   public Long getId () { return id; }
   public List<ChildObject> getAttrs () { return attrs; }
}

ChildObject:

@Entity
public class ChildObject {
   @Embeddable
   public static class Pk implements Serializable {
       @Column(name = "parentId", nullable=false, updatable=false)
       private Long objectId;

       @Column(nullable=false, updatable=false)
       private String name;

       @Column(nullable=false, updatable=false)
       private int pos;
       ...
   }

   @EmbeddedId
   private Pk id;

   @ManyToOne
   @JoinColumn(name="parentId", insertable = false, updatable = false)
   @org.hibernate.annotations.ForeignKey(name = "FK_CHILD_OBJECT_PARENTID")
   private ParentObject parent;

   public Pk getId () { return id; }
   public ParentObject getParent () { return parent; }
}
于 2010-04-10T00:41:58.800 に答える
12

親とparentIdを別々にマップするのではなく、ParentObject参照をに組み込む必要があります。ChildObject.Pk

(ゲッター、セッター、問題に関係のないHibernate属性、およびメンバーアクセスキーワードは省略)

class ChildObject { 
    @Embeddable
    static class Pk {
        @ManyToOne...
        @JoinColumn(name="parentId")
        ParentObject parent;

        @Column...
        String name...
        ...
    }

    @EmbeddedId
    Pk id;
}

ParentObjectあなたにそれから置くだけでそれ@OneToMany(mappedBy="id.parent")は機能します。

于 2013-11-15T13:27:00.037 に答える
4

まず、で、に設定する必要ParentObjectのある属性を「修正」します。また(これはタイプミスかもしれませんが)注釈を追加します:mappedBy"parent"@Id

@Entity
public class ParentObject {
    @Id
    @GeneratedValue
    private String id;

    @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
    @IndexColumn(name = "pos", base=0)
    private List<ObjectChild> attrs;

    // getters/setters
}

次に、で、複合キーのに属性をObjectChild追加します。nameobjectId

@Entity
public class ObjectChild {
    @Embeddable
    public static class Pk implements Serializable {
        @Column(name = "parentId", nullable = false, updatable = false)
        private String objectId;

        @Column(nullable = false, updatable = false)
        private String name;

        @Column(nullable = false, updatable = false)
        private int pos;
    }

    @EmbeddedId
    private Pk pk;

    @ManyToOne
    @JoinColumn(name = "parentId", insertable = false, updatable = false)
    private ParentObject parent;

    // getters/setters

}

また、このエンティティのマッピングで列を繰り返しているため、に追加insertable = false, updatable = falseします。@JoinColumnparentId

これらの変更により、エンティティの永続化と読み取りは正常に機能しています(Derbyでテスト済み)。

于 2010-04-10T01:40:36.120 に答える
3

多くの実験と欲求不満の末、私は最終的に自分がやりたいことを正確に行うことができないと判断しました。

最終的に、私は先に進み、子オブジェクトに独自の合成キーを与え、Hibernateにそれを管理させました。キーは残りのデータとほぼ同じ大きさであるため、これは理想的ではありませんが、機能します。

于 2010-04-15T18:58:41.740 に答える
1

問題の答えを探してこの質問を見つけましたが、それは私の問題を解決しませんでした。私が探して@OneToManyいたテーブル構造に適していないものを探していたからです。@ElementCollection私の場合はぴったりです。ただし、その落とし穴の1つは、行IDだけでなく、リレーションの行全体が一意であると見なしていることです。

@Entity
public class ParentObject {
@Column(nullable=false, updatable=false)
@Id @GeneratedValue(generator="...")
private String id;

@ElementCollection
@CollectionTable( name = "chidren", joinColumns = @JoinColumn( name = "parent_id" ) )
private List<ObjectChild> attrs;

...
}

@Embeddable
public static class ObjectChild implements Serializable {
    @Column(nullable=false, updatable=false)
    private String parentId;

    @Column(nullable=false, updatable=false)
    private String name;

    @Column(nullable=false, updatable=false)
    private int pos;

    @Override
    public String toString() {
        return new Formatter().format("%s.%s[%d]", parentId, name, pos).toString();
    }

    ... getters and setters REQUIRED (at least they were for me)
}
于 2015-08-12T23:23:41.767 に答える
0

あなたはかなり近づいたようです、そして私は私の現在のシステムで同じことをしようとしています。私は代理キーから始めましたが、親のPKとリスト内のインデックスで構成される複合主キーを優先して削除したいと思います。

「外部」ジェネレーターを使用して、マスターテーブルからPKを共有する1対1の関係を取得することができました。

@Entity
@GenericGenerator(
    name = "Parent",
    strategy = "foreign",
    parameters = { @Parameter(name = "property", value = "parent") }
)
public class ChildObject implements Serializable {
    @Id
    @GeneratedValue(generator = "Parent")
    @Column(name = "parent_id")
    private int parentId;

    @OneToOne(mappedBy = "childObject")
    private ParentObject parentObject;
    ...
}

@GenericGeneratorと@GeneratedValueを追加して、Hibernateが挿入中に親の新しく取得したPKを割り当てないという問題を解決できるかどうか疑問に思います。

于 2010-10-01T18:48:01.897 に答える
0

Parentオブジェクトを保存した後、Childオブジェクトへの挿入を機能させるには、ChildオブジェクトにparentIdを明示的に設定する必要があります。

于 2013-01-31T13:20:33.907 に答える
0

これに3日間費やした後、私は解決策を見つけたと思いますが、正直なところ、私はそれが好きではなく、間違いなく改善することができます。しかし、それは機能し、私たちの問題を解決します。

これがエンティティコンストラクターですが、setterメソッドでも実行できます。また、Collectionオブジェクトを使用しましたが、Listと同じか類似している必要があります。

...
public ParentObject(Collection<ObjectChild> children) {
    Collection<ObjectChild> occ = new ArrayList<ObjectChild>();
    for(ObjectChild obj:children){
        obj.setParent(this);
        occ.add(obj);
    }
    this.attrs = occ;
}
...

基本的に、他の誰かが提案したように、親を(すべての子とともに)保存する前に、まずすべての子の親IDを手動で設定する必要があります

于 2017-04-14T14:56:31.967 に答える
0

私はひどく答えを探していましたが、実用的な解決策を見つけることができませんでした。親にOneToManyが正しく、子にManyToOneが正しくありましたが、親の保存中に、子のキーが割り当てられず、親から自動生成された値が割り当てられていませんでした。

子エンティティ(Javaクラス)の@ManyToOneマッピングの上にアノテーションjavax.persistence.MapsIdを追加すると、問題が修正されました。

@MapsId("java_field_name_of_child's_composite_key_that_needs_the_value_from_parent")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_ID", nullable = false, insertable = false, updatable = false)
private Parent parent;

これは、@ Pascal Thiventが回答した内容(2010年4月10日1:40に回答)に加えてです。

このスレッドの前半にある彼の投稿のサンプルコードスニペットを参照してください。

ありがとう、PJR。

于 2020-02-24T22:47:23.413 に答える