MatthiasN
MatthiasN

Reputation: 1

JPA : initializing simultaneously both entities in a parent/child relations

I'm new to JPA and I can't find a way to correctly initialize a set of child entities when saving the parent using its own repository.

I have this Parent entity which contains a list of child that I want to instantiate when creating the parent such as :

@Entity(name = "parent")
@Table(schema = "XXX", name = "PARENT")
public class Parent {

    @Id
    @GeneratedValue
    @Column(name = "ID_PARENT", nullable = false)
    private int idParent;

    @OneToMany(targetEntity = Child.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "ID_PARENT", referencedColumnName = "ID_PARENT")
    private List<Child> childList= new ArrayList<>();

    // Constructor + getters/setters...

The child class (the key of the table is composed of a parent id + its own id, don't ask why) :

@Entity(name = "child")
@Table(schema = "XXX", name = "CHILD")
@IdClass(ChildPrimaryKey.class)
public class Child{

    @Id
    @Column(name = "ID_CHILD", nullable = false)
    private int idChild;

    @Id
    @Column(name = "ID_PARENT", nullable = false)
    private int idParent;


    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Parent.class)
    @JoinColumn(name = "ID_PARENT", nullable = false, insertable = false, updatable = false)
    private Parent parent;

    // Constructor + getters/setters...

And finally the ChildPrimaryKey class :

public class ChildPrimaryKey implements Serializable {

    private static final long serialVersionUID = XXXL;
   
    private int idChild;

    private int idParent;

    // Constructors + getters/setters
    

The problem I'm facing is that there isn't a direct link between the parentId field of the Child class and its parent field. So when I save a Parent entity (with a list of Child initialized inside the childList field) using its repository (basic CrudRepository with some custom queries), then the Parent is correctly saved with its ID getting a generated value, as wanted. But then the Child entities are saved but without the correct ID generated for the parent (by default 0 since it's an int I guess ?), resulting in a constraint violation exception since the column ID_PARENT should refer to an actual Parent id.

I've tried using @PrimaryKeyJoinColumn like this :

@Entity(name = "child")
@Table(schema = "XXX", name = "CHILD")
@IdClass(ChildPrimaryKey.class)
public class Child{

    @Id
    @Column(name = "ID_CHILD", nullable = false)
    private int idChild;
 
    @Id
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Parent.class)
    @PrimaryKeyJoinColumn(name = "ID_PARENT", referencedColumnName = "ID_PARENT")
    private Parent parent;

   // Constructor + getters/setters...

In this case, since the field idParent doesn't exist in the Child class, I get a compilation error because the ChildPrimaryKey class expects the field to be present, plus I need it for my repository queries. (I've also tried adding a int field as before but it still doesn't get any value)

Can anyone explain me what am I doing wrong ? How can I correctly transfer the generated id of the parent when the children are created ?

I would like to avoid having to create the parent first, then getting it's ID to then create the children individually giving them the correct one.

Upvotes: 0

Views: 285

Answers (1)

Christian Beikov
Christian Beikov

Reputation: 16420

Use this model:

@Entity(name = "parent")
@Table(schema = "XXX", name = "PARENT")
public class Parent {

    @Id
    @GeneratedValue
    @Column(name = "ID_PARENT", nullable = false)
    private int idParent;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Child> childList = new ArrayList<>();

}

@Entity(name = "child")
@Table(schema = "XXX", name = "CHILD")
@IdClass(ChildPrimaryKey.class)
public class Child {

    @Id
    @Column(name = "ID_CHILD", nullable = false)
    private int idChild;
 
    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_PARENT")
    private Parent parent;
}
public class ChildPrimaryKey implements Serializable {

    private static final long serialVersionUID = XXXL;
   
    private int idChild;
    private int parent;
}

Upvotes: 0

Related Questions