Подтвердить что ты не робот

Сохранять дочерние объекты автоматически с помощью JPA Hibernate

У меня есть отношение "один ко многим" между родительской и дочерней таблицей. В родительском объекте у меня есть

List<Child> setChilds(List<Child> childs)

У меня также есть внешний ключ в таблице Child. Этот внешний ключ является идентификатором, который ссылается на родительскую строку в базе данных. Поэтому в моей конфигурации базы данных этот внешний ключ не может быть NULL. Также этот внешний ключ является первичным ключом в родительской таблице.

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

session.save(parent);

Я пробовал выше, но я получаю ошибку базы данных, жалуясь, что поле внешнего ключа в таблице Child не может быть NULL. Есть ли способ сообщить JPA автоматически установить этот внешний ключ в объект Child, чтобы он мог автоматически сохранять дочерние объекты?

Спасибо заранее.

4b9b3361

Ответ 1

Я пробовал выше, но я получаю ошибку базы данных, жалуясь, что поле внешнего ключа в таблице Child не может быть NULL. Есть ли способ сообщить JPA автоматически установить этот внешний ключ в объект Child, чтобы он мог автоматически сохранять дочерние объекты?

Ну, здесь есть две вещи.

Во-первых, вам нужно каскадировать операцию сохранения (но я понимаю, что вы это делаете или вы не получите нарушение ограничения FK во время вставок в "дочерней" таблице)

Во-вторых, у вас, вероятно, есть двунаправленная связь, и я думаю, что вы не устанавливаете "обе стороны ссылки" правильно. Вы должны сделать что-то вроде этого:

Parent parent = new Parent();
...
Child c1 = new Child();
...
c1.setParent(parent);

List<Child> children = new ArrayList<Child>();
children.add(c1);
parent.setChilds(children);

session.save(parent);

Общим примером является использование методов управления ссылками:

@Entity
public class Parent {
    @Id private Long id;

    @OneToMany(mappedBy="parent")
    private List<Child> children = new ArrayList<Child>();

    ...

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

    public void addToChildren(Child child) {
        child.setParent(this);
        this.children.add(child);
    }
}

И код будет выглядеть следующим образом:

Parent parent = new Parent();
...
Child c1 = new Child();
...

parent.addToChild(c1);

session.save(parent);

Ссылки

Ответ 2

Я считаю, что вам нужно установить параметр каскада в вашем сопоставлении через xml/annotation. Обратитесь к Пример ссылки Hibernate здесь.

Если вы используете аннотацию, вам нужно сделать что-то вроде этого,

@OneToMany(cascade = CascadeType.PERSIST) // Other options are CascadeType.ALL, CascadeType.UPDATE etc..

Ответ 3

Вот способы назначения родительского объекта в дочернем объекте двунаправленных отношений <

Предположим, что у вас есть отношение "Один-ко-многим", то для каждого родительского объекта существует набор дочерних объектов. В двунаправленных отношениях каждый дочерний объект будет иметь ссылку на своего родителя.

eg : Each Department will have list of Employees and each Employee is part of some department.This is called Bi directional relations.

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

Parent parent = new Parent();
...
Child c1 = new Child();
...
c1.setParent(parent);

List<Child> children = new ArrayList<Child>();
children.add(c1);
parent.setChilds(children);

session.save(parent);

Другой способ: вы можете использовать hibernate Intercepter, таким образом, вы не сможете писать код выше для всех моделей.

Перехватчик Hibernate предоставляет apis для выполнения вашей собственной работы перед выполнением любой операции с БД. Подобно onSave объекта мы можем назначить родительский объект в дочерних объектах с использованием отражения.

public class CustomEntityInterceptor extends EmptyInterceptor {

    @Override
    public boolean onSave(
            final Object entity, final Serializable id, final Object[] state, final String[] propertyNames,
            final Type[] types) {
        if (types != null) {
            for (int i = 0; i < types.length; i++) {
                if (types[i].isCollectionType()) {
                    String propertyName = propertyNames[i];
                    propertyName = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                    try {
                        Method method = entity.getClass().getMethod("get" + propertyName);
                        List<Object> objectList = (List<Object>) method.invoke(entity);

                        if (objectList != null) {
                            for (Object object : objectList) {
                                String entityName = entity.getClass().getSimpleName();
                                Method eachMethod = object.getClass().getMethod("set" + entityName, entity.getClass());
                                eachMethod.invoke(object, entity);
                            }
                        }

                    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return true;
    }

}

И вы можете зарегистрировать Intercepter для конфигурации как

new Configuration().setInterceptor( new CustomEntityInterceptor() );

Ответ 4

Используйте org.hibernate.annotations для выполнения Cascade, если используются hibernate и JPA, его как-то жалуются на сохранение дочерних объектов.

Ответ 5

в ваших setChilds, вы можете попробовать выполнить цикл через список и сделать что-то вроде

child.parent = this;

вы также должны настроить каскад родителя на соответствующие значения.

Ответ 6

В следующей программе описывается, как двунаправленное отношение работает в спящем режиме.        Когда родитель сохранит свой список дочерних объектов, будет автоматически сохранено.

      @Entity
      @Table(name="clients")
     public class Clients implements Serializable  {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)     
     @OneToMany(mappedBy="clients", cascade=CascadeType.ALL)
      List<SmsNumbers> smsNumbers;

    on the parent side
     and put the following annotation on the child side




 @Entity
  @Table(name="smsnumbers")
 public class SmsNumbers implements Serializable {
   @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
   int id;
   String number;
   String status;
 Date reg_date;
 @ManyToOne
 @JoinColumn(name = "client_id")
 private Clients clients;
  and getter setter.





    public static void main(String arr[])
   {
       Session session = HibernateUtil.openSession();
     //getting transaction object from session object
       session.beginTransaction();

        Clients cl=new Clients("Murali", "1010101010");
          SmsNumbers sms1=new SmsNumbers("99999", "Active", cl);
          SmsNumbers sms2=new SmsNumbers("88888", "InActive", cl);
          SmsNumbers sms3=new SmsNumbers("77777", "Active", cl);
          List<SmsNumbers> lstSmsNumbers=new ArrayList<SmsNumbers>();
          lstSmsNumbers.add(sms1);
          lstSmsNumbers.add(sms2);
          lstSmsNumbers.add(sms3);
          cl.setSmsNumbers(lstSmsNumbers);
     session.saveOrUpdate(cl);
     session.getTransaction().commit(); 
    session.close();