Java: Hibernate @OneToOne mapping
Asked Answered
B

2

26

I'm trying to get Hibernate @OneToOne annotations working and not having much success here...

Let's say I've got a table called status that looks like this:

+------------------------------------------------+
|                     status                     |
+------------------------------------------------+
| id | frn_user_id | frn_content_id |   status   |
+----+-------------+----------------+------------+
|  1 |     111     |        0       |  "active"  |
+----+-------------+----------------+------------+
|  2 |      0      |       222      | "inactive" |
+----+-------------+----------------+------------+

And I've got an entity for User that looks like this:

@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", nullable = false)
    private Integer id;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "userId")
    private Status status;

    // getters and setters
}

And a similar one for Content, and another entity for Status that looks like this:

@Entity
@Table(name = "status")
public class Status {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "frn_user_id")
    private Integer userId;

    @Column(name = "frn_content_id")
    private Integer contentId;

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

    // getters and setters
}

When I perform a read on User, I expect that User.getStatus() will return a Status object with id=1. Instead, I get an AnnotationException: "Referenced property not a (One|Many)ToOne: Status.userId in mappedBy User.status"

I've poured through docs, tutorials and examples here on SO, but everything I've tried so far has failed.

Also worth noting: This should support a one-to-zero-or-one relationship, as some user and content records will not have a reference in the status table.

Any help would be greatly appreciated!

Blanco answered 13/2, 2014 at 18:17 Comment(5)
userId needs to be of type User with a @OneToOne/@JoinColumn on it. Also note you have a typo (contentId/userId)Correspondent
see also #18304022Correspondent
Just a database design idea: maybe you could reconsider your design as a many-to-many relationship between users and contents, and the status description would be in that design a user attribute?Icosahedron
Thanks @RC. I didn't realize it had to be an object.Blanco
@Icosahedron Yeah the DB design is not ideal but I'm stuck using it for the time being..Blanco
D
77

Your Status entity must not have properties userId and contentId of type Integer, mapped with @Column. It must have properties user and content of type User and Content, mapped with @OneToOne:

public class User {
    @OneToOne(mappedBy = "user")
    private Status status;
    // ...
}

public class Status {
    @OneToOne
    @JoinColumn(name = "frn_user_id")
    private User user;
    // ...
}

A user has one status. A status has one user.

Dinky answered 13/2, 2014 at 18:23 Comment(4)
Thanks for sharing this. I was stucked on mappedBy from last 3 days. I Googled & go through so many Stackoverflow posts for this, but no luck at all. When I go through your solution, then I remember I have created a java.util.Set in OneToOne mapping on the reverse side of relation. As soon as I removed the Set & just create Entity type property, my code starts working. Thank you so much. Upvote.Gagne
I am a bit confused after gone through @Vlad Mihalcea Answer on this post. In his answer, Child has many toys then why he has annotated List<Toy> toys with OneToOne(mappedBy = "child") ? Why not with OneToMany ? Also you have specified JoinColumn on User in Status & Vlad Mihalcea didn't on Child in Toy. What is the objective of mappedBy with/without JoinColumn ? Will you please clear my doubt ?Gagne
It's wrong. It should be OneToMany. JoinColumn is used to specify the name of the join column. If you don't specify one, Hibernate will use a defaukt name (How this default name is constructed name is specified in the JPA spec)Dinky
I used the same code as you mentioned here. But still I get the frn_user_id as nullUndis
H
0

use this way. Add below field in Customer entity.

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "customer")
private Status status;

and don't add getter and setter for status field in Customer entity. And add below code to Status Entity.

@OneToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "customer_id", nullable = false)
private Customer customer;

Here add the getter and setter for customer field in Status Entity class. You can see one working example here.

Hellenize answered 2/11, 2019 at 10:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.