JPA: одновременная инициализация обоих объектов в отношениях родитель/потомок

Я новичок в JPA и не могу найти способ правильно инициализировать набор дочерних объектов при сохранении родительского объекта с использованием собственного репозитория.

У меня есть родительский объект, который содержит список дочерних элементов, экземпляр которых я хочу создать при создании родительского объекта, например:

      @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...

Дочерний класс (ключ таблицы состоит из родительского идентификатора + собственного идентификатора, не спрашивайте почему):

      @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...

И, наконец, класс ChildPrimaryKey:

      public class ChildPrimaryKey implements Serializable {

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

    private int idParent;

    // Constructors + getters/setters
    

Проблема, с которой я столкнулся, заключается в том, что между полем ParentId класса Child и его родительским полем нет прямой связи. Поэтому, когда я сохраняю родительский объект (со списком дочерних элементов, инициализированных внутри поля childList), используя его репозиторий (базовый CrudRepository с некоторыми пользовательскими запросами), тогда родительский объект правильно сохраняется, а его идентификатор получает сгенерированное значение, как и хотелось. Но затем дочерние объекты сохраняются, но без правильного идентификатора, сгенерированного для родительского объекта (по умолчанию 0, поскольку, я думаю, это целое число?), что приводит к исключению нарушения ограничения, поскольку столбец ID_PARENT должен ссылаться на фактический родительский идентификатор.

Я пробовал использовать @PrimaryKeyJoinColumn следующим образом:

      @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...

В этом случае, поскольку поле idParent не существует в классе Child, я получаю ошибку компиляции, поскольку класс ChildPrimaryKey ожидает присутствия этого поля, плюс оно мне нужно для запросов к хранилищу.(Я также пытался добавить поле int, как и раньше, но оно все равно не получило никакого значения)

Может ли кто-нибудь объяснить мне, что я делаю неправильно? Как я могу правильно передать сгенерированный идентификатор родителя при создании дочерних элементов?

Я хотел бы избежать необходимости сначала создавать родительский элемент, а затем получать его идентификатор, чтобы затем создавать дочерние элементы индивидуально, давая им правильный идентификатор.

1 ответ

Используйте эту модель:

      @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;
}
Другие вопросы по тегам