JPA Hibernate One-To-One Relationship

Hibernate - @OneToOne relation

First of all I have to say that I would not suggest you to use @Data lombok annotation with hibernate entity class. See for example this article.

Then, I would suggest you to correct your Review entity mapping in this way:

import javax.persistence.Transient;

@Entity
@Table(name = "review")
public class Review
{
private String reviewId;
private Book book;

@Id
@Column(name = "review_id")
public String getReviewId()
{
return reviewId;
}

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "book_isn")
public Book getBook()
{
return book;
}

// setters omitted for brevity

@Transient
public String getBookId()
{
return book != null ? book.getBookId() : null;
}
}

You can persist your Review entities in the following way:

Book b1 = new Book();
b1.setBookId("BK1");
b1.setBookName("Book 1");

Review r1 = new Review();
r1.setReviewId("R1");
r1.setBook(b1);

session.persist(r1);

Review r2 = new Review();
r2.setReviewId("R2");
session.persist(r2); // book_isn is NULL for the R2 Review

P.S. Please also note that it is not recommended to use string as a type for primary key for big tables due to the potential performance problem.

Hibernate: OneToOne: two fields of the same type

I don't think there is an easy way to implement this bidirectional mapping with a OneToOne (as the others pointed out, this is not really a one-to-one association). Even if there was, I would argue your model would not be readable or easy to understand given the domain model requirements: when you say "an Animal can only have one Person that likes them", we shouldn't expect to have two Person fields in the Animal class, we should expect simply one.

You can drop the bidirectional mapping and opt for a simple unidirectional association for each Animal in the Person:

@Entity
@SequenceGenerator(name="PERSON_SEQ", sequenceName="person_sequence")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="PERSON_SEQ")
private Long id;

@Column
private String name;

public Person() {}

@OneToOne
@JoinColumn(name = "firstAnimal")
private Animal firstAnimal;

@OneToOne
@JoinColumn(name = "secondAnimal")
private Animal secondAnimal;

...
}

@Entity
@SequenceGenerator(name="PRIVATE_SEQ", sequenceName="private_sequence")
public class Animal {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="PRIVATE_SEQ")
private Long id;

@Column
private String name;

@OneToOne
@JoinColumn(name = "person")
private Person person;

...
}

Java hibernate OneToOne: which side should be the owner

Q2: same examples put mappedBy in the USER_DETAILS side,
why people want to do this ?
How to determine which side to put mappedBy ?

In a bidirectional relationship, each entity has a relationship field
or property that refers to the other entity. Through the relationship
field or property, an entity class’s code can access its related
object. If an entity has a related field, the entity is said to “know”
about its related object.

There is a bidirectional one-to-one relationship in your example. Both User and UserDetail entities have a relationship field. @OneToOne annotation specified on both the entities.

For one-to-one bidirectional relationships, the owning side
corresponds to the side that contains the corresponding foreign key.

The owner of the relationship is UserDetail entity. The owner has @JoinColumn annotation to specify foreign key (USR_ID).

Inverse side of relationship (User) has mappedBy attribute.

Q1: so USER is the owner, if it calls save(),
USER_DETAILS table will be updated as well ?

In your example UserDetail is the owner. Therefore the saving process:

User user = new User();  // Ignoring the constructor parameters...
UserDetail userDetail = new UserDetail();

user.setUserDetail(userDetail);
userDetail.setUser(user);

userRepository.save(user);

You only need to save the parent. It will save the child as well.

JPA Hibernate One-to-One relationship

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.



Related Topics



Leave a reply



Submit