Reputation: 567
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
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
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
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