Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data JPA insert with child along with parent entity by taking id from parent

I want to save Parent entity along with child entity into MySQL database by just calling save on parent. There is one to one mapping between Parent and Child entities. Parent ID is auto generated and we need to use same in the child as child's pk also.

I am using Spring Data JPA 2.0 (the JPA provider is Hibernate) and Spring MVC framework. When are tried to insert entity I am getting following error.

root cause

org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: com.serro.cbmapi.model.Child.parent; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: com.serro.cbmapi.model.Child.parent org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:207)

Here is My DB Schema:

Parent Table:
   CREATE TABLE `parent` (
   `pid` int(11) NOT NULL AUTO_INCREMENT,
   `parent_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
    PRIMARY KEY (`pid`)    ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1;

    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Child Table:
    CREATE TABLE `child` (
    `cid` int(11) NOT NULL,
    `child_name` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
    PRIMARY KEY (`cid`),
    CONSTRAINT `child_f1` FOREIGN KEY (`cid`) REFERENCES `parent` (`pid`)

    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Here is my Java Entity Parent Entity:

@Entity(name="parent")
@NamedQuery(name="Parent.findAll", query="SELECT p FROM parent p")
public class Parent implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private int pid;

    @Column(name="parent_name")
    private String parentName;

    //bi-directional one-to-one association to Child
    @OneToOne(mappedBy="parent",cascade=CascadeType.ALL)
    private Child child;

    //getter, setters
}

Child Enity:

@Entity(name="child")
@NamedQuery(name="Child.findAll", query="SELECT c FROM child c")
public class Child implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private int cid;

    @Column(name="child_name")
    private String childName;

    //bi-directional one-to-one association to Parent
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="cid")
    @MapsId("cid")
    private Parent parent;

    //getter, setters
}

Here is my Main method

AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
ParentRepository parentResp = context.getBean(ParentRepository.class);  
Parent parent = new Parent();
parent.setParentName("Parent1");
Child child = new Child();
child.setChildName("Child1");
parent.setChild(child);
parentResp.save(parent);
like image 777
Mangesh Pathak Avatar asked Aug 25 '14 16:08

Mangesh Pathak


1 Answers

You should use cascade in both your objects. Try this:

@Entity(name="parent")
public class Parent implements Serializable {
    //...
    @OneToOne(mappedBy="parent",cascade=CascadeType.ALL)
    private Child child;
    //...
}

@Entity(name="child")
public class Child implements Serializable {
    //...
    @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @JoinColumn(name="cid", referencedColumnName = "id")
    private Parent parent;
    //...
}
like image 136
Viacheslav Shalamov Avatar answered Sep 28 '22 01:09

Viacheslav Shalamov