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
How to Initialize an Arraylist with All Zeroes in Java
How to Read Numeric Strings in Excel Cells as String (Not Numbers)
Is a Volatile Int in Java Thread-Safe
Generating a Jaxb Class That Implements an Interface
How to Create a Stream from an Array
How to Create a Topic in Kafka from the Ide Using API
Multiple Java Versions Running Concurrently Under Windows
How to Create an Object of an Interface
Detect and Extract Url from a String
Java - How to Load Different Versions of the Same Class
Hibernate Criteria: Joining Table Without a Mapped Association
Using Jaxb to Unmarshal/Marshal a List<String>
Adding in Clause List to a JPA Query