Thursday, March 8, 2007

Hibernate: Annotation one-to-one (primary-key)

Hibernate Doc (Chap 8.2.2)


::Relationship::
person(one) -> address(one)


::DB Schema::
person( personId )
address( personId )
* address's primary key is same as person's primary key


::Java Operation::
person.getAddress();


::Annotation::
@Entity
@Table(name="PERSON")
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="personId")
private int id;

@OneToOne
@PrimaryKeyJoinColumn
private Address address;

public Address getAddress() {
return address;
}
}

@Entity
@Table(name = "ADDRESS")
public class Address {
@Id
@Column(name = "personId")
private int id;
}



::Generated SQL (mysql5.0)::
- person.getAddress();
select person0_.personId as personId2_2_, address1_.personId as personId3_0_, person2_.personId as personId2_1_ from PERSON person0_ left outer join ADDRESS address1_ on person0_.personId=address1_.personId left outer join PERSON person2_ on address1_.personId=person2_.personId where person0_.personId=?

[Association Mapping List]

10 comments:

Kishore said...

In your DB SChema you mentioned as address( addressId )

but in Entity mapping you mentioned as personId, is there something I am missing?

James said...

This doesn't seem to be totally complete. Could you also explain a Bi-directional case as well? Thanks.

avilardo said...

Thanks....this post is a too important reference!!

help said...

give proper examples please

Anonymous said...

Given Example is quite confusing.
Let me add new example.

@Entity
public class Body {


@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;

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

@OneToOne(cascade=CascadeType.ALL)
@PrimaryKeyJoinColumn
private Heart heart;

@Column(name="id")
public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}


public Heart getHeart()
{
return heart;
}

}


@Entity
public class Heart {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;

private String status;


public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

}


Schma :
Body Id,name
Heart Id,status

Nirav Assar said...

JPA alone does not support shared primary key generation. You will need to use hibernate's extension annotation for custom generator. In the blog example the Person has an auto generated Id. The address does not have any generator. Thus you get the exception that "id needs to be set".

The solution is to use @GeneratedValue and @GenericGenerator which will get the Person's primary key and use it for the address.

Nirav Assar said...

I wrote a blog article on this same topic.

http://assarconsulting.blogspot.com/2009/08/one-to-one-shared-primary-key.html

Shiv Pratap said...

This example is a fake one developer are fooled by forcing the column to have the same name. The blog is great, but particularly for this example please refer to some other source.

Shiv Pratap said...

I performed the test with hibernate 3 jars on Mysql database. The result was with id 1 in person table and id 0 in Address table , there is no way to relate both these entries, my concern is that i am trying to persist only the person object which is having an associate address object, so if the frame work is taking the responsibility of saving the asoociate object then it should either relate them while firing an insert query or at last by update query and if not able to perform any of the task (due to some issues) shouls throw an exception.

Anonymous said...

Excellent resource. Thank you!!