Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't hibernate lazily fetch @ManyToOne and @OneToOne?

After some frustrating issues and tests, I've read that hibernate can't lazily fetch ToOne relationships.

From what I've read, hibernate lazily fetches ToMany by setting its own Set as a proxy, and when a method is called on that Set, it fetched the data in the database before performing the action. Fine.

For ToOne, the reason I've seen is that since the attribute can be null (unlike ToMany), hibernate has to know whether it needs to populate it with null or a proxy, and that hibernate cannot know that without querying the other table. And since it has to query that other table, it eagerly fetches the data at the same time.

I find that rather stupid. I can understand it on the non owning side of the relationship, where nothing in the table indicates whether the toOne is populated, but on the owning side, the table contains a column with the foreign key, which is either null or not.

Why can't hibernate query the table and set the attribute to either null or a proxy depending on the value from that column? It doesn't need to check the second table, if your column is not null, you know the second table has a corresponding entry (and if it hasn't, you have an integrity problem and hibernate should just throw).

like image 863
elcye Avatar asked Nov 06 '22 03:11

elcye


1 Answers

Hibernate behaves more or les how you descibed.

On the owning side hibernate supports Lazy loading, it's just not enabled by default. You need to add it @OneToOne(fetch = FetchType.LAZY)

But when you have that mapped bidirectionaly (on both entities), as you said hibernate needs to query the table to decide between null or proxy. So devs decided to eager load the whole entity. Regardless of the fetch type.

You can avoid theese problems by getting rid of the foreign key and just use same primary key vaue.

You can do that with @MapsId annotation on the owning side.

@Entity
public class Owning {
 
    @Id
    private Long id;
 
    @OneToOne
    @MapsId
    @JoinColumn(name = "id")
    private Child child;
 
}
like image 144
Pavel Polivka Avatar answered Nov 11 '22 05:11

Pavel Polivka