Java 使用 JPA Hibernate 自动保存子对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3927091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 07:02:34  来源:igfitidea点击:

Save child objects automatically using JPA Hibernate

javadatabasehibernate

提问by Marquinio

I have a one-to-many relation between Parent and Child table. In the parent object I have a

我在父表和子表之间存在一对多关系。在父对象中,我有一个

List<Child> setChildren(List<Child> childs)

I also have a foreign key in the Child table. This foreign key is an ID that references a Parent row in database. So in my database configuration this foreign key can not be NULL. Also this foreign key is the primary key in the Parent table.

我在 Child 表中也有一个外键。此外键是引用数据库中父行的 ID。所以在我的数据库配置中,这个外键不能为 NULL。这个外键也是父表中的主键。

So my question is how I can automatically save the children objects by doing something like this:

所以我的问题是如何通过执行以下操作来自动保存子对象:

session.save(parent);

I tried the above but I'm getting a database error complaining that the foreign key field in the Child table can not be NULL. Is there a way to tell JPA to automatically set this foreign key into the Child object so it can automatically save children objects?

我尝试了上述操作,但出现数据库错误,抱怨 Child 表中的外键字段不能为 NULL。有没有办法告诉 JPA 自动将此外键设置到 Child 对象中,以便它可以自动保存子对象?

Thanks in advance.

提前致谢。

采纳答案by Pascal Thivent

I tried the above but I'm getting a database error complaining that the foreign key field in the Child table can not be NULL. Is there a way to tell JPA to automatically set this foreign key into the Child object so it can automatically save children objects?

我尝试了上述操作,但出现数据库错误,抱怨 Child 表中的外键字段不能为 NULL。有没有办法告诉 JPA 自动将此外键设置到 Child 对象中,以便它可以自动保存子对象?

Well, there are two things here.

嗯,这里有两件事。

First, you need to cascade the save operation (but my understanding is that you are doing this or you wouldn't get a FK constraint violation during inserts in the "child" table)

首先,您需要级联保存操作(但我的理解是您正在执行此操作,否则在“子”表中插入期间不会出现 FK 约束冲突)

Second, you probably have a bidirectional association and I think that you're not setting "both sides of the link" correctly. You are supposed to do something like this:

其次,您可能有双向关联,我认为您没有正确设置“链接的两侧”。你应该做这样的事情:

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

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

session.save(parent);

A common pattern is to use link management methods:

一种常见的模式是使用链接管理方法:

@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);
    }
}

And the code becomes:

代码变为:

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

parent.addToChildren(c1);

session.save(parent);
参考

回答by hvgotcodes

in your setChilds, you might want to try looping thru the list and doing something like

在您的 setChilds 中,您可能想尝试遍历列表并执行类似的操作

child.parent = this;

you also should set up the cascade on the parent to the appropriate values.

您还应该将父级上的级联设置为适当的值。

回答by Adeel Ansari

I believe you need to set the cascade option in your mapping via xml/annotation. Refer to Hibernate reference example here.

我相信您需要通过 xml/annotation 在映射中设置级联选项。请参阅此处的 Hibernate 参考示例

In case you are using annotation, you need to do something like this,

如果您使用注释,则需要执行以下操作,

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

回答by Sunil Kumar

Here are the ways to assign parent object in child object of Bi-directional relations ?

以下是在双向关系的子对象中分配父对象的方法?

Suppose you have a relation say One-To-Many,then for each parent object,a set of child object exists. In bi-directional relations,each child object will have reference to its parent.

假设您有一个关系说一对多,那么对于每个父对象,存在一组子对象。在双向关系中,每个子对象都将引用其父对象。

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

To achieve this, one wayis to assign parent in child object while persisting parent object

为此,一种方法是在持久化父对象的同时在子对象中分配父对象

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);

Other wayis, you can do using hibernate Intercepter,this way helps you not to write above code for all models.

另一种方法是,您可以使用休眠拦截器,这种方式可以帮助您不必为所有模型编写上述代码。

Hibernate interceptor provide apis to do your own work before perform any DB operation.Likewise onSave of object, we can assign parent object in child objects using reflection.

在执行任何数据库操作之前,Hibernate 拦截器提供 apis 来完成您自己的工作。同样,对象的保存,我们可以使用反射在子对象中分配父对象。

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;
    }

}

And you can register Intercepter to configuration as

您可以将拦截器注册为配置

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

回答by sandhya nayak

Use org.hibernate.annotationsfor doing Cascade, if the hibernateand JPAare used together , its somehow complaining on saving the child objects.

使用org.hibernate.annotations这样做Cascade,如果hibernateJPA一起使用时,其节约的子对象莫名其妙地抱怨。

回答by shriram

Following program describe how bidirectional relation work in hibernate.

以下程序描述了双向关系如何在休眠中工作。

When parent will save its list of child object will be auto save.

当父对象保存其子对象列表时,将自动保存。

On Parent side:

在父母方面:

    @Entity
    @Table(name="clients")
    public class Clients implements Serializable  {

         @Id
         @GeneratedValue(strategy = GenerationType.IDENTITY)     
         @OneToMany(mappedBy="clients", cascade=CascadeType.ALL)
          List<SmsNumbers> smsNumbers;
    }

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.

 }

Main class:

主要类:

 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();    

 }

回答by Dila Gurung

In short set cascade type to all , will do a job; For an example in your model. Add Code like this . @OneToMany(mappedBy = "receipt", cascade=CascadeType.ALL) private List saleSet;

总之将级联类型设置为 all ,就可以了;以您的模型为例。像这样添加代码。@OneToMany(mappedBy = "receipt", cascade=CascadeType.ALL) 私有列表 saleSet;