2017-02-13 21 views
0

カスケードを正しく動作させるためにクラスに適切な注釈を付ける方法を理解しようとしています。Hibernate OneToManyのカスケード問題

ここでは単純な親子シナリオを示します。

子供:

@Entity 
@Table(name = "testChild") 
public class testChild implements Serializable { 
    @Id 
    @GeneratedValue(generator = "uuid") 
    @GenericGenerator(name = "uuid", strategy = "uuid2") 
    @Column(name = "uuid", unique = true, nullable = false) 
    @JsonProperty 
    private String uuid; 

    @ManyToOne(fetch = FetchType.EAGER) 
    @JoinColumn(name="parent_uuid", nullable=false) 
    @Cascade(value={CascadeType.ALL}) 
    @JsonIgnore 
    private testParent parent; 

    @Column(name = "name") 
    @JsonProperty 
    private String name;  

    public testChild (testParent parent, String name) { 
     this.uuid = UUID.randomUUID().toString(); 
     this.name = name; 
     this.parent = parent; 
    } 

    public String getUuid() { 
     return this.uuid; 
    } 

    public void setUuid(String uuid) { 
     this.uuid = uuid; 
    } 

    public String getName() { 
     return this.name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public testParent getParent() { 
     return this.parent; 
    } 

    public void setParent (testParent parent) { 
     this.parent = parent; 
    } 
} 

親:

@Entity 
@Table(name = "testParent") 
public class testParent implements Serializable { 
    @Id 
    @GeneratedValue(generator = "uuid") 
    @GenericGenerator(name = "uuid", strategy = "uuid2") 
    @Column(name = "uuid", unique = true, nullable = false) 
    @JsonProperty 
    private String uuid;  // This is the figure uuid:<number> 

    @Column(name = "name") 
    @JsonProperty 
    private String name;  

    @Column(name = "children") 
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", orphanRemoval=true, cascade = javax.persistence.CascadeType.ALL) 
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE}) 
    @JsonProperty 
    private List <testChild> children;  

    public testParent (String name) { 
     this.uuid = UUID.randomUUID().toString(); 
     this.name = name; 
     this.children = new ArrayList<>(); 
    } 

    public String getUuid() { 
     return this.uuid; 
    } 

    public void setUuid(String uuid) { 
     this.uuid = uuid; 
    } 

    public String getName() { 
     return this.name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public List <testChild> getChildren() { 
     return this.children; 
    } 

    public void setChildren (List <testChild> children) { 
     this.children = children; 
    } 

    public testChild addChild(String childname) { 
     testChild c = new testChild(this, childname); 
     this.children.add(c); 
     return c; 
    } 
} 

とテストコード:

testParent p = new testParent("Dan"); 
sid = p.getUuid(); 

testChild c1 = p.addChild("Dan jr."); 
testChild c2 = p.addChild("Dannielle"); 
session.save(p); 

私の問題は、それが代わりに(最初の)子へのアップデートが生じていますということです挿入物の:

DEBUG org.hibernate.SQL - insert into testParent (name, uuid) values (?, ?) 
DEBUG org.hibernate.SQL - update testChild set name=?, parent_uuid=? where uuid=? 

もちろん、これはエラーをスローします。 私は親クラスと子クラスの両方でCascadeのかなりの組み合わせを試しました。

私が明示的に "session.save(object)"を常時使用していることが唯一のことです。すなわち 親を作成する - 子を作成する - 保存する、 作成するchild2 - 保存する、 最後に親をもう一度保存します。

私は本当にHibernateに、上から下にすべてを保存するように指示する方法を知りたいと思います。

このサイトや他のサイトからさまざまな提案がありましたが、何も問題はありません。

答えて

0

私は部分的な答えがあります。それは問題を解決しますが、私はまだ少し混乱しています。 問題は、生成されたIDを使用することと関係しています。私も手動で設定しようとしていましたが、親と子のマッピングを壊していたと思います。ここで

は、いくつかの作業コードです:

try { 
     testParent p = new testParent("Dan"); 
     sid = p.getUuid(); 

     testChild c1 = new testChild("Dan Jr."); 
     testChild c2 = new testChild("Danielle"); 

     c1.setParent(p); 
     c2.setParent(p); 
     p.getChildren().add(c1); 
     p.getChildren().add(c2); 

     session.save(p);    
     tx.commit(); 

    } catch(Exception e) { 
     tx.rollback(); 
     log.error("Exception occured. "+e.getMessage()); 
     assertTrue(false); 
    } 

しかし、私は二つのことを行うときにのみ動作します:クラス定義から@GeneratedValue@GenericGenerator注釈を削除

  1. を。
  2. 私のコンストラクタがこれらのidフィールドを手動で作成することを確認してください。

私はそうしないと、setUuidはDBに保存されているときにuuidフィールドを更新しないようです。オブジェクトは新しいIDを取得しますが、最初に生成されたIDのみが保存されます。

これを行うには、これが最善の方法かどうかと思います。

0

親と子のために明示的にセッターを使用する必要があります。ここで

は、あなたがしなければならないものです:

testParent p = new testParent("Dan"); 

testChild c1 = new testChild("Dan"); 
testChild c2 = new testChild("Dannielle"); 

c1.setParent(p); 
c2.setParent(p); 

p.getChildren().add(c1); 
p.getChildren().add(c2); 
session.save(p); 

あなたはまた、おそらくエンティティカスケードを混同しました。 OneToMany側では、testParentの場合はCascadeType.ALLにするか、CascadeType.PERSISTを含める必要があります。親を「挿入する」、「更新する」、または「削除する」としたいときはいつでも、子どもに対しても同じ操作をしてください。

親のsaveは、その参照された子にも保存をカスケードする必要があります。

+0

しかし、私はすでにaddChildメソッドでそれをやっています。 – DanTheMan

+0

@DanTheManが私の答えを編集しました。親オブジェクトは既定でその子として既存のリストを持つので、その参照を取得し、子オブジェクトを追加して、これらが関連しており、1対多の関係として「永続化」する必要があると言う必要があります。 また、お互いを「認識」するためには、その子にも親を設定する必要があります。これを試して、変更がどのような違いを見たかを確認する必要があります。 –

+0

@DanTheManあなたは子供の親も同様に設定しましたか? –

関連する問題