Reputation: 127
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);
Upvotes: 7
Views: 20821
Reputation: 21445
The exception
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
says that the parent
property in your Child
object is null
.
So to fix this you need to add this line of code:
child.setParent(parent);
Also as per the JPA Docs:
Designates a ManyToOne or OneToOne relationship attribute that provides the mapping for an EmbeddedId primary key, an attribute within an EmbeddedId primary key, or a simple primary key of the parent entity. The value element specifies the attribute within a composite key to which the relationship attribute corresponds. If the entity's primary key is of the same Java type as the primary key of the entity referenced by the relationship, the value attribute is not specified.
your parent
field in Child
class should be declared without the value
attribute for @MapsId
:
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="cid")
@MapsId
private Parent parent;
Upvotes: 2
Reputation: 4427
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;
//...
}
Upvotes: 3