使用JPA Hibernate自动保存子对象

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

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

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

所以我的问题是,我可以通过做这样的事情自动保存子对象:

 session.save(parent); 

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

提前致谢。

我试过以上,但我得到一个数据库错误抱怨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); 

常见的模式是使用链接pipe理方法:

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

参考

  • Hibernate核心参考指南
    • 1.2.6。 工作双向链接

我相信你需要通过xml / annotation在映射中设置级联选项。 这里请参考Hibernate的参考例子 。

如果你使用注释,你需要做这样的事情,

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

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

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

 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来完成自己的工作。同样在保存对象的时候,我们可以使用reflection来指定父对象在子对象中。

 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注册为configuration

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

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

在你的setChilds中,你可能想要尝试通过列表循环,并做类似的事情

 child.parent = this; 

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

以下程序描述了双向关系如何在hibernate中工作。 当父母将保存它的子对象的列表将被自动保存。

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