简体   繁体   中英

Lazy loading issue with One to one association in hibernate

I have a question related to lazy loading of OneToOne association mapping.

Case 1 Foreign key is in Child table (Address)

@Entity
public class User {
    ..........
    @OneToOne(mappedBy="user")
    private Address address;


@Entity
public class Address{
    .........
    @OneToOne
    @JoinColumn(name = "user_id")
    private User user;

In the above Address lazy loading doesn't work.

Case 2 Foreign key is in Parent table (User)

@Entity
public class User {
    .............
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="address_id")
    private Address address;


@Entity
public class Address {
    ........
    @OneToOne(mappedBy="address")
    private User user;

In the above Address lazy loading works.

Could please someone explain me why One to one lazy loading doesn't work in first case but works in second?

@OneToOne is a bit tricky to handle.

It all depends on what persistence provider you're using.

Some providers do not respect FetchType.LAZY hint.

You can try to specify (on both ends of relation)

@OneToOne(optional = true, fetch = FetchType.LAZY)

To understand what happens here lets take a look at the level:

first case:

+-----------------+             +------------------+
| USER            |             |  Address         |
|                 |1           1|                  |
|                 +-------------+  USER_ID (FK)    |
|                 |             |                  |
|                 |             |                  |
+-----------------+             +------------------+

When you load the user Hibernate has to know if the Address is present or not.

So Hibernate issues a SQL request similar to this:

SELECT * FROM USER WHERE ID = ?
SELECT * FROM ADDRESS WHERE user_id = ?

When getting the result the entity is already loaded, so it's no point to assign a LazyProxy to the Address. Hibernate assigns the fetched object.

Second case:

+-----------------+             +------------------+
| USER            |             |  Address         |
|                 |1           1|                  |
| ADDRESS_ID      +-------------+                  |
|                 |             |                  |
|                 |             |                  |
+-----------------+             +------------------+

SELECT * FROM USER WHERE ID = ?

Hibernate does not need to check if the Address is there or not. That's why the proxy is created.

I haven't been able to make it work, so I wound up using a prepared statement where I JOIN FETCH the things that Hibernate was querying for after-the-fact anyhow.

Adding optional=true or faking a OneToMany relationship are, IMO, wrong ways to fix this.

Read this article. It will give you understanding why one to one on inverse side (mapped by) attribute does not work as expected. One to One Lazy explanation .

Actually on inverse side hibernate needs to know what is the value of mapping, because user can ask for value immediately.

Read the article and you will get clear understanding how things work.

Thanks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM