web-dev-qa-db-ja.com

1対多の関係を持つJPA Persist親と子

20個の子エンティティを持つ親エンティティを保持したい、私のコードは以下です

親クラス

@OneToMany(mappedBy = "parentId")
private Collection<Child> childCollection;

子クラス

@JoinColumn(name = "parent_id", referencedColumnName = "parent_id")
@ManyToOne(optional=false)
private Parent parent;

String jsonString = "json string containing parent properties and child  collection" 

ObjectMapper mapper = new ObjectMapper();
Parent parent = mapper.readValue(jsonString, Parent.class);

public void save(Parent parent) {
    Collection<Child> childCollection = new ArrayList<>() ;

    for(Child tha : parent.getChildCollection()) { 
        tha.setParent(parent);
        childCollection.add(tha);
    }

    parent.setChildCollection(childCollection);
    getEntityManager().persist(parent);
 }

したがって、20個の子テーブルがある場合、それらのそれぞれに親参照を設定する必要があり、そのためには20個のforループを記述する必要がありますか?実行可能ですか?親と子を自動的に永続化できる他の方法または構成はありますか?

18
Gora

親クラスを修正します。

@OneToMany(mappedBy = "parent")

mappedByプロパティは、関係の反対側のフィールドを指す必要があります。 JavaDoc のように:

関係を所有するフィールド。関係が単方向でない場合は必須です。

また、周期的に子エンティティを明示的に永続化する必要があります。

for(Child tha : parent.getChildCollection()) { 
    ...
    getEntityManager().persist(tha);
    ...
}

Alan Hay のコメントにあるように、カスケード機能を使用して、EntityManagerにすべての子エンティティを自動的に永続化させることができます。

@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)

カスケード(およびJPA自体)の詳細については、 Vlad Mihalceaのブログ を参照してください。

10
Ivan Babanin

通常、@ JoinColumnは、エンティティが関係の所有者であることを示し、mappedByは、エンティティが関係の逆であることを示します。

したがって、次のようにしようとしている場合

@OneToMany(mappedBy = "parent")
private Collection<Child> childCollection;

つまり、関係の逆であり、親参照をその子に設定しません。

親参照をその子に設定するには、上記のエンティティ関係の所有者を次の方法で作成する必要があります。

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn
private Collection<Child> childCollection;

上記のコードは子テーブルに列を作成するため、子参照を設定する必要はありません。

7
maruf571

コメントで指摘されているように、オブジェクトグラフの子/親関係との整合性に注意する必要があります。 JSONが直接、つまりPOST=リクエストから来ている場合、この一貫性は解放されません。

親フィールドと子フィールドに_@JsonBackReference_および_@JsonManagedReference_の注釈を付ける必要があります。

親クラス:

_@OneToMany(mappedBy = "parentId")
@JsonBackReference
private Collection<Child> childCollection;
_

子クラス:

_@JoinColumn(name = "parent_id", referencedColumnName = "parent_id")
@ManyToOne(optional=false)
@JsonManagedReference
private Parent parent;
_

答えのある同様の質問は here です

さらに、Lombokの_@JsonBackReference_注釈と組み合わせて_@JsonManagedReference_注釈付きクラスで_javax.persistence_/_@ToString_を使用すると、stackoverflowエラーが発生します。

@ToString( exclude = ...)で_@ToString_注釈からchildCollectionおよびparentフィールドを除外するだけです

Lombokで生成されたequals()メソッド(_@Data_、_@EqualsAndHashCode_)でも同じことが起こります。これらのメソッドを手動で実装するか、_@Getter_および_@Setter_注釈のみを使用して実装します。

5
s17t.net

親に自分の子を永続させます

package com.greg;

import Java.util.ArrayList;
import Java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;

@Entity(name = "PARENT")
public class Parent {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

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

    @Column(name = "DESCRIPTION")
    private String description;

    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name = "parent", referencedColumnName = "id", nullable = false)
    private List<Child> children = new ArrayList<Child>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<Child> getChildren() {
        return children;
    }

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

}
2
Essex Boy