Hibernate: joining entities



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.

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;
}


Source: stackoverflow