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.
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:
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);
}