hibernatecascadeone-to-onebidirectional-relationhibernate-cascade

Two problems in a @OneToOne relationship


I am using Hibernate 4.3.6.Final, and WildFly 16. I have two problems with a @OneToOne relationship.

1.) First problem: Unknown mappedBy in: at.home.digest.model.Expose.home, referenced property unknown: at.home.digest.model.Home.expose"}}

These are my entitites:

@Entity
@Table(name = "home",
    uniqueConstraints =  @UniqueConstraint (columnNames = {"URL"})
)
@Access(AccessType.FIELD)
public class Home implements Serializable { 

    @OneToOne (fetch = FetchType.LAZY, mappedBy = "home", cascade = CascadeType.ALL)
    @JoinColumn(name = "expose_id")
    private Expose expose;

    public Expose getExpose() {
        return expose;
    }

    public void setExpose(Expose expose) {
        this.expose = expose;
    }
    ................

}

Expose entity:

@Entity
@Table(name ="expose")
@Access(AccessType.FIELD)
public class Expose  implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "id", updatable=false, nullable=false)
    private int id; 

    @OneToOne (fetch = FetchType.EAGER, mappedBy = "expose", cascade=CascadeType.PERSIST )
    @JoinColumn(name = "home_id")
    private Home home;

    @ManyToOne ( optional = false, cascade=CascadeType.MERGE )
    @JoinColumn(name = "contact_id")
    private Contact contact;

}

Upon deployment of the application I recieve:

Caused by: org.hibernate.AnnotationException: Unknown mappedBy in: at.home.digest.model.Expose.home, referenced property unknown: at.home.digest.model.Home.expose"}}

2.) Second problem: First, I overcome the first problem by removing the attribute mappedBy = "expose" from the Expose entity, i.e. Expose entity now looks like:

@Entity
@Table(name ="expose")
@Access(AccessType.FIELD)
public class Expose  implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "id", updatable=false, nullable=false)
    private int id; 


    @OneToOne (fetch = FetchType.EAGER, cascade=CascadeType.PERSIST )
    @JoinColumn(name = "home_id")
    private Home home;

    @ManyToOne ( optional = false, cascade=CascadeType.MERGE )
    @JoinColumn(name = "contact_id")
    private Contact contact;

    }

Now I am not facing the first problem anymore. However, when saving a home entity, it does not refer the corresponding expose entity anymore. Instead, the field expose_id in the SQL table home is null.:

Here is my source code to save the entitties:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void saveEntity(Home home) throws EntityExistsException {

    Expose expose = null;
    if (home.getExpose() != null && home.getExpose().getContact() != null) {
        Contact contact = this.em.merge(home.getExpose().getContact());
        home.getExpose().setContact(contact);
        expose = this.em.merge(home.getExpose());
        home.setExpose(expose);
    }
    this.em.persist(home);
    if (expose != null) {
        expose.setHome(home);
        expose = this.em.merge(expose);
        home.setExpose(expose);
        this.em.merge(home);
    }
}

A Home entity havin a corresponding expose entity is saved without a reference to the corresponding expose entity, i.e. the expose_id column in the home table is null. The corresponding expose entity is saved with a reference to the home entity though, i.e. the column home_id in the expose table is correctly referencing the corresponding row in the home table.


Solution

  • I was not entirely able to explain where the error is. However, I solved the problem as follows:

    1.) I saved my MySQL Database in a file (using mysqldump), then dropped the entire database.

    2.) As I am using MySQL Server 5.7, I needed to change the Hibernate Dialect in my persistence.xml to

    org.hibernate.dialect.MySQL57Dialect 
    

    (earlier it was org.hibernate.dialect.MySQLDialect). I also set the property hibernate.hbm2ddl.auto to create in order for hibernate to create all my tables anew upon next deployment of the application

    3.) I changed my hibernate @OneToOne mappings between Home and Expose following the article here:

    https://hellokoding.com/jpa-one-to-one-shared-primary-key-relationship-mapping-example-with-spring-boot-maven-and-mysql/

    In this way Expose and Home are now sharing one and the same primary key, which counts for increased efficiency. My Home and Expose entities are now as follows:

    @Entity
    @Table(name = "home",
        uniqueConstraints =  @UniqueConstraint (columnNames = {"URL"})
    )
    @Access(AccessType.FIELD)
    public class Home implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id; 
    
    
        @OneToOne (fetch = FetchType.LAZY,  mappedBy = "home", cascade = CascadeType.ALL)
        private Expose expose;
    
        // ..... setters and getters here
    
    }
    
    @Entity
    @Table(name ="expose")
    @Access(AccessType.FIELD)
    public class Expose  implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @Id
        private int id; 
    
        @OneToOne (fetch = FetchType.LAZY)
        @JoinColumn (name = "id")
        @MapsId
        private Home home;
    
            // ..... setters and getters here
    
    }
    

    4.) The code that saves a home entity looks like this now:

        @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
        public void updateEntityWithExpose(Home home) throws EntityExistsException {
            Expose expose = null;
            if (home.getExpose() != null && home.getExpose().getContact() != null) {
                Contact contact = this.em.merge(home.getExpose().getContact());
                home.getExpose().setContact(contact);
            }
            this.em.persist(home);
        }