Hibernate zeroToOne

3.2k Views Asked by At

I am trying to establish a relationship between 2 entities which would be zero-to-one. That is, the Parent can be saved without the associated Child entity and also along with the assoicated Child. Following are the 2 Entity classes...


Employee (Parent)

public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name="EMP_NAME")
    private String name;

    @PrimaryKeyJoinColumn
    @OneToOne(cascade = {CascadeType.ALL})
    private EmployeeInfo info;

    @Column(name="EMP_ENUM")
    private Integer enumId;

EmployeeInfo (Child)

public class EmployeeInfo {
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;

        @Column(name="EMPLOYEE_EMAIL")
        private String email;

With such kind of a relation and id column of the only Parent (Employee) table set to AUTO INCREMENT in MySql DB, the problem is that while saving a Parent->Child object graph, I get the following exception

org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [insert into EMP_INFO 
Caused by: java.sql.SQLException: Field 'id' doesn't have a default value

I tried setting the Child Table's Id property to AUTO INCREMENT in the DB , and the persistence of such a Parent->Child object graph is successful. However, the problem described here surfaces, because I have a scenario in which I would like to save the parent (Employee) object without the associated EmpInfo object, and hence do NOT want to have AUTO INCREMENT on the Child's id column.


One solution could be not use the PrimaryKeyJoinColumn, but use a particular JoinColumn, but that adds an unnecessary column to my existing Table.


Has anyone come across such a problem? If yes, any pointers would be much helpful.

2

There are 2 best solutions below

10
On

I have a scenario in which I would like to save the parent (Employee) object without the associated EmpInfo object.

The optional attribute of a OneToOne is true by default, which is what you want.

However, you are somehow misusing the @PrimaryKeyJoinColumn here (well, it actually depends on what you really want to achieve but your current combination of annotations is not correct).

IF you want to map a OneToOne with a shared primary-key, use the @PrimaryKeyJoinColumn. But in that case, don't use a GeneratedValue on EmployeeInfo and set the id manually or, if you don't want to set it manually, use the Hibernate specific foreign generator that I already mentioned in your previous question. Check also the related question mentioned below.

And IF you do not want to use a shared primary key (like in your current code since you're trying to get the id generated by the database), then do not use the PrimaryKeyJoinColumn.

You have to make a choice.

References

  • JPA 1.0 specification:
    • 9.1.32 PrimaryKeyJoinColumn Annotation

Related question

0
On

Finally, I got it working thanks to Pascal and some googling from my side. Apparently, I cannot use the Native key generator for such relationships where the parent can exist without the child (optional = true). The thing that worked finally was the following, leaving me the downside of having to deal with Hibernate specific annotation (@GenericGenerator) and also having to make-do with bi-directional relationships instead of the unidirectional that I wanted.

Employee (Parent) class remains unchanged as above. It has AUTO INCREMENT on the Id column.

As for the child class (EmployeeInfo) it changed to the following, and again WITHOUT having the AUTO INCREMENT set on the Id column.

@Table(name="EMP_INFO")
@Entity
public class EmployeeInfo {
    @Id
    @GeneratedValue(generator="foreign")
    @GenericGenerator(name="foreign", strategy = "foreign", parameters={
    @Parameter(name="property", value="verifInfo")}) 
    private Long id;

    @OneToOne(optional=false)
    @JoinColumn (name="id")
    private Employee emp;

    @Column(name="EMPLOYEE_EMAIL")
    private String email;

This helped me achieve what I wanted but on the downside, GenericGenerator is not a JPA annotation, it is a hibernate annotation, and sadly I have to make do with that as of now because JPA does not currently support this(or any similar) annotation.

Anyway, it helps to get through such cases :-)