I am using Hibernate Core version 5.4.25.Final in my Java application.
As a Hibernate novice, I was hoping to be able to get a simple version of joining entities together but I am currently unable to do so.
Entity 1 (simplified):
@Entity(name = "Message") @Table(name = MSG_TABLE, schema = MY_SCHEMA) public class Message { @Column(name = "message_id", nullable = false) @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long messageId; @JsonIgnore @OneToOne @JoinColumn(name = "message_id", referencedColumnName = "message_id") private MessageJourney messageJourney; public void myMethod() { log.debug("Message id {}", messageId); log.debug("Message journey exists: {}", messageJourney != null); } }
Entity 2 (simplified):
@Entity(name = "MsgJourney") @Table(name = MSG_JOURNEY_TABLE, schema = MY_SCHEMA) @NoArgsConstructor public class MessageJourney { @Id @Column(name = "message_journey_id") private Long id; @Column(name = "message_id") private Long messageId; }
If I call myMethod() for a specific object of type Message, the following output gets logged:
Message id 163348 Message journey exists: false
Doing a query on the database shows that this is not correct – a Message Journey record does exist for Message id 163348. If I run the following query in the database:
select m.message_id, mj.message_journey_id from schema.messages m inner join schema.message_journey mj on m.message_id = mj.message_id where m.message_id = 163348;
… I get 1 row returned.
Therefore, I can only conclude that this relatively simple joining of entities via Hibernate isn’t working for some reason, although I cannot work out why. My understanding was the @OneToOne joins should be eagerly loaded, so the Message’s MessageJourney should be immediately available.
Any assistance would be gratefully received – thanks.
Advertisement
Answer
First of all, I hope you are reading a book or doing a tutorial to understand the mapping capabilities as an understanding is vital to the success.
Your mapping should in fact work, but you didn’t show how you are querying, so it’s hard to say what is wrong.
My understanding was the @OneToOne joins should be eagerly loaded
This is not necessarily true. You can configure this, but by default associations are eager loaded.
I would recommend the following mapping:
@Entity(name = "Message") @Table(name = MSG_TABLE, schema = MY_SCHEMA) public class Message { @Column(name = "message_id", nullable = false) @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long messageId; @JsonIgnore @OneToOne(mappedBy = "message") private MessageJourney messageJourney; public void myMethod() { log.debug("Message id {}", messageId); log.debug("Message journey exists: {}", messageJourney != null); } } @Entity(name = "MsgJourney") @Table(name = MSG_JOURNEY_TABLE, schema = MY_SCHEMA) @NoArgsConstructor public class MessageJourney { @Id @Column(name = "message_journey_id") private Long id; @OneToOne @JoinColumn(name = "message_id") private Message message; }
I hope you are aware that OneToOne
implies that the FK also needs to be unique i.e. message_id
in MSG_JOURNEY_TABLE
has to be unique. I don’t know your requirements but my gut tells me what you want is a @ManyToOne
instead.
@Entity(name = "Message") @Table(name = MSG_TABLE, schema = MY_SCHEMA) public class Message { @Column(name = "message_id", nullable = false) @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long messageId; @JsonIgnore @OneToMany(mappedBy = "message") private Set<MessageJourney> messageJourney = new HashSet<>(); public void myMethod() { log.debug("Message id {}", messageId); log.debug("Message journey exists: {}", !messageJourney.isEmpty()); } } @Entity(name = "MsgJourney") @Table(name = MSG_JOURNEY_TABLE, schema = MY_SCHEMA) @NoArgsConstructor public class MessageJourney { @Id @Column(name = "message_journey_id") private Long id; @ManyToOne @JoinColumn(name = "message_id") private Message message; }