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

a2mppw5e  于 2022-12-21  发布在  Java
关注(0)|答案(9)|浏览(257)

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

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

我在子表中也有一个外键。此外键是引用数据库中父行的ID。因此,在我的数据库配置中,此外键不能为NULL。此外,此外键是父表中的主键。
所以我的问题是,如何通过执行以下操作来自动保存子对象:

session.save(parent);

我尝试了上面的方法,但是我得到了一个数据库错误,抱怨Child表中的外键字段不能为NULL。有没有办法告诉JPA自动将这个外键设置到Child对象中,以便它可以自动保存子对象?

yhived7q

yhived7q1#

我尝试了上面的方法,但是我得到了一个数据库错误,抱怨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.setChildren(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.addToChildren(c1);

session.save(parent);

参考

  • Hibernate核心参考指南
  • 1.2.6.工作双向链路
ddhy6vgd

ddhy6vgd2#

我认为您需要通过xml/annotation在Map中设置cascade选项,请参考Hibernate reference example here
如果您正在使用注解,则需要执行以下操作,

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

hc2pp10m3#

下面的程序描述了双向关系在Hibernate中是如何工作的。
当父对象将保存其子对象列表时,将自动保存。
在父端:

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

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

并将以下注解放在子端:

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

 }
2jcobegt

2jcobegt4#

在setChilds中,您可能希望尝试循环遍历列表并执行以下操作

child.parent = this;

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

lymgl2op

lymgl2op5#

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

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

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

另一种方法是,您可以使用hibIntercepter,这种方法有助于您不必为所有型号编写上述代码。

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

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

ct3nt3jp6#

在JPA @*To*关系中,父实体和子实体必须在(父)保存之前交叉分配。

icnyk63a

icnyk63a7#

使用org.hibernate.annotations执行Cascade,如果hibernateJPA一起使用,它不知何故会抱怨保存子对象。

qyzbxkaa

qyzbxkaa8#

总之将级联式设置为全部,就可以完成工作;在您的模型中添加一个示例。像这样添加代码。@OneToMany(mappedBy =“receipt”,cascade=CascadeType.ALL)private List saleSet;

omhiaaxx

omhiaaxx9#

如果您没有双向关系,并且只想保存/更新子表中的单列,那么您可以创建具有子实体的JPA存储库,并调用save/saveAll或update方法。

    • 注意:**如果您遇到FK冲突,则意味着您的 Postman 请求(具有主键和外键id)与子表中生成的id不匹配,**检查您的请求和子表中要更新的id(它们应该匹配/如果不匹配则意味着您遇到FK冲突)**无论在事务之前保存父表和子表时生成了什么id,当您尝试更新子表中的单列时,这些id都应该在第二次调用中匹配。

母公司:

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

     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)  
     private UUID customerId ;
     
     @OneToMany(cascade = CascadeType.ALL) 
     @JoinColumn(name ="child_columnName", referencedColumnName= 
                "parent_columnName")
     List<Accounts> accountList;
}

孩子:

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

         @Id
         @GeneratedValue(strategy = GenerationType.IDENTITY)  
         private UUID accountid;
         
        
    }

相关问题