JPA Hibernate One-to-One relationship

JavaHibernateJpa

Java Problem Overview


I have a one-to-one relationship but hibernatetool complains when generating the schema. Here's an example that shows the problem:

@Entity
public class Person {
    @Id
    public int id;

    @OneToOne
    public OtherInfo otherInfo;

    rest of attributes ...
}

Person has a one-to-one relationship with OtherInfo:

@Entity
public class OtherInfo {
    @Id
    @OneToOne(mappedBy="otherInfo")
    public Person person;

    rest of attributes ...
}

Person is owning side of OtherInfo. OtherInfo is the owned side so person uses mappedBy to specify the attribute name "otherInfo" in Person.

I get the following error when using hibernatetool to generate the database schema:

org.hibernate.MappingException: Could not determine type for: Person, at table: OtherInfo, for columns: [org.hibernate.mapping.Column(person)]
        at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:292)
        at org.hibernate.mapping.SimpleValue.createIdentifierGenerator(SimpleValue.java:175)
        at org.hibernate.cfg.Configuration.iterateGenerators(Configuration.java:743)
        at org.hibernate.cfg.Configuration.generateDropSchemaScript(Configuration.java:854)
        at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.java:128)
        ...

Any idea why? Am I a doing something wrong or is this a Hibernate bug?

Java Solutions


Solution 1 - Java

JPA doesn't allow the @Id annotation on a OneToOne or ManyToOne mapping. What you are trying to do is one-to-one entity association with shared primary key. The simplest case is unidirectional one-to-one with shared key:

@Entity
public class Person {
    @Id
    private int id;

    @OneToOne
    @PrimaryKeyJoinColumn
    private OtherInfo otherInfo;

    rest of attributes ...
}

The main problem with this is that JPA provides no support for shared primary key generation in OtherInfo entity. The classic book Java Persistence with Hibernate by Bauer and King gives the following solution to the problem using Hibernate extension:

@Entity
public class OtherInfo {
    @Id @GeneratedValue(generator = "customForeignGenerator")
    @org.hibernate.annotations.GenericGenerator(
        name = "customForeignGenerator",
        strategy = "foreign",
        parameters = @Parameter(name = "property", value = "person")
    )
    private Long id;

    @OneToOne(mappedBy="otherInfo")
    @PrimaryKeyJoinColumn
    public Person person;

    rest of attributes ...
}

Also, see here.

Solution 2 - Java

This should be working too using JPA 2.0 @MapsId annotation instead of Hibernate's GenericGenerator:

@Entity
public class Person {
	
	@Id
	@GeneratedValue
	public int id;

	@OneToOne
	@PrimaryKeyJoinColumn
	public OtherInfo otherInfo;
	
	rest of attributes ...
}

@Entity
public class OtherInfo {
	
	@Id
	public int id;
	
	@MapsId
	@OneToOne
	@JoinColumn(name="id")
	public Person person;
	
	rest of attributes ...
}

More details on this in Hibernate 4.1 documentation under section 5.1.2.2.7.

Solution 3 - Java

You just need to add @JoinColumn(name="column_name") to Host Entity relation . column_name is the database column name in person table.

@Entity
public class Person {
    @Id
    public int id;

    @OneToOne
    @JoinColumn(name="other_info")
    public OtherInfo otherInfo;

    rest of attributes ...
}

Person has a one-to-one relationship with OtherInfo: mappedBy="var_name" var_name is variable name for otherInfo in Person class.

@Entity
public class OtherInfo {
    @Id
    @OneToOne(mappedBy="otherInfo")
    public Person person;

    rest of attributes ...
}

Solution 4 - Java

I think you still need the primary key property in the OtherInfo class.

@Entity
public class OtherInfo {
    @Id
    public int id;

    @OneToOne(mappedBy="otherInfo")
    public Person person;

    rest of attributes ...
}

Also, you may need to add the @PrimaryKeyJoinColumn annotation to the other side of the mapping. I know that Hibernate uses this by default. But then I haven't used JPA annotations, which seem to require you to specify how the association wokrs.

Solution 5 - Java

I have a better way of doing this:

@Entity
public class Person {

    @OneToOne(cascade={javax.persistence.CascadeType.ALL})
    @JoinColumn(name = "`Id_OtherInfo`")
    public OtherInfo getOtherInfo() {
      return otherInfo;
    }

}

That's all

Solution 6 - Java

I'm not sure you can use a relationship as an Id/PrimaryKey in Hibernate.

Solution 7 - Java

Try this

@Entity

@Table(name="tblperson")

public class Person {
    
public int id;

public OtherInfo otherInfo;
@Id //Here Id is autogenerated
@Column(name="id")
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
	return id;
}
public void setId(int id) {
	this.id = id;
}

@OneToOne(cascade = CascadeType.ALL,targetEntity=OtherInfo.class)
@JoinColumn(name="otherInfo_id") //there should be a column otherInfo_id in Person
public OtherInfo getOtherInfo() {
	return otherInfo;
}
public void setOtherInfo(OtherInfo otherInfo) {
	this.otherInfo= otherInfo;
}
rest of attributes ...
}


@Entity

@Table(name="tblotherInfo")

public class OtherInfo {

private int id;

private Person person;

@Id

@Column(name="id")
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
	return id;
}
public void setId(Long id) {
	this.id = id;
}

  @OneToOne(mappedBy="OtherInfo",targetEntity=Person.class)	  
public College getPerson() {
	return person;
}
public void setPerson(Person person) {
	this.person = person;
}    
 rest of attributes ...
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSteve KuoView Question on Stackoverflow
Solution 1 - JavatopchefView Answer on Stackoverflow
Solution 2 - JavaMariuszView Answer on Stackoverflow
Solution 3 - JavaIgor SadovnikovView Answer on Stackoverflow
Solution 4 - JavawaxwingView Answer on Stackoverflow
Solution 5 - JavaVodo-Siosk BaasView Answer on Stackoverflow
Solution 6 - JavarazenhaView Answer on Stackoverflow
Solution 7 - JavaJugalView Answer on Stackoverflow