user1731299
user1731299

Reputation: 567

Hibernate - bidirectional @OneToOne

I have 2 classes: User and UserPicture which have a 1:1 relationship.

public class User {
     @Id
     @GeneratedValue(strategy=GenerationType.AUTO)
     @Column(name="id", nullable = false, unique = true)
 private int id;

     private String firstname;

     private String lastname;

     @OneToOne
     @JoinColumn(name = "picture") //field named "picture" in the database
     private UserPicture userPicture;

     ..
}


public class UserPicture {

     @Id
     @GeneratedValue(strategy=GenerationType.AUTO)
     @Column(name="id", nullable = false, unique = true)
     private int id;

     private Blob image;

     @OneToOne
     @JoinColumn(name = "user")
     User user;

'user' in UserPicture will be loaded but 'userPicture' in User not - what did Im wrong?

EDIT Have to add that Im just create a UserPicture and insert them (with existing userId) - maybe I need to cascade 'user' in UserPicture?

Upvotes: 14

Views: 31949

Answers (3)

Vaibhav Bansal
Vaibhav Bansal

Reputation: 137

Lazy loading in One to One works even when we specify the field as non nullable in the JoinColumn annotation. However in a bidirectional One to One the lazy loading doesn't work on the entity where we use mappedBy=''. For eg if we have two entities Contract and House, where Contract table holds a foreign key to House. When we use bidirectional OneToOne here and try to load contract then lazy loading works(i.e. House is not loaded eagerly) but when we try to load House (using House repository) then the Contract is always fetched eagerly. Does anybody have an idea why this happens?

Public class Contract {
  .....
  @onetoone(lazy)
  @JoinColumn(name='houseid', nullable=false)
  Private House house
  .....
}

Public class House {
  .....
  @onetoone(lazy, mappedBy='house')
  Private Contract contract
  .....
}

I know this is only a partial answer, cum question. But it is very much related to the discussion here.

Upvotes: 2

AForsberg
AForsberg

Reputation: 1194

In regards to your question: (because I don't have enough reputation to respond in a comment)

"All clear! Only one question more, is it possible to make userPicture in User lazy? – user1731299 Oct 24 '12 at 10:44"

Yes, it -is- possible to make it lazy fetch. However, just saying "fetchType=FetchType.Lazy" will not work. Reason being, Hibernate needs to check the joined table to see if it's a null value, or if there's a record there. Since it's a OneToOne mapping, Hibernate figures that it can save a database call by just pulling back any data that's there, since it had to check if it was null anyways. This isn't the case for x-to-many-mappings, since Hibernate knows that the 'many' means there's a list waiting on the other table... be it an empty or a populated list, it's still a list. For a single value, it has to differentiate between the actual data and a null value.

The way around this is to tell Hibernate that there will ALWAYS be a value there, and NEVER a null value. Knowing this, Hibernate can create a place-holder until it's time to fetch that data. The way you do this in annotations is to add "optional=false" to your @OneToOne annotation.

However be cautioned! There are some issues with this; including the one I'm trying to figure out now (and how I came to stumble across your question here). This optional=false makes Hibernate do a little extra validation and seems to confuse Hibernate on how it should execute inserts. So, you may want to stay away from this lazy fetching technique.

Upvotes: 7

Pigueiras
Pigueiras

Reputation: 19356

You have to map your classes.

public class User {
    ...
    @OneToOne (mappedBy="user")
    private UserPicture userPicture;
    ...
}

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

Upvotes: 21

Related Questions