I had a similar problem:
- I did Session.save(nastyItem) to save an object into the Session.
However, I did not fill in the property buyer which is mapped as update="false" insert="false" (this happens a lot when you have a composed primary key, then you map the many-to-one's as insert="false" update="false")
- I a query to load a list of items, and the item which I just saved, happens to be part of the result set
- now what goes wrong? Hibernate sees that the item was already in the cache, and Hibernate does not replace (probably not to break my earlier reference nastyItem) it with the newly loaded value, but uses MY nastyItem I have put into the Session cache myself. Even worse, now the lazy loading of the buyer is broken: it contains null.
To avoid these Session issues, I always do a flush and a clear after a save, merge, update or delete. Having to solve these nasty problems takes too much of my time.
First off, some clarifications to KLE's answer:
Unconstrained (nullable) one-to-one association is the only one that can not be proxied without bytecode instrumentation. The reason for this is that owner entity MUST know whether association property should contain a proxy object or NULL and it can't determine that by looking at its base table's columns due to one-to-one normally being mapped via shared PK, so it has to be eagerly fetched anyway making proxy pointless. Here's a more detailed explanation.
many-to-one associations (and one-to-many, obviously) do not suffer from this issue. Owner entity can easily check its own FK (and in case of one-to-many, empty collection proxy is created initially and populated on demand), so the association can be lazy.
Replacing one-to-one with one-to-many is pretty much never a good idea. You can replace it with unique many-to-one but there are other (possibly better) options.
Rob H. has a valid point, however you may not be able to implement it depending on your model (e.g. if your one-to-one association is nullable).
Now, as far as original question goes:
A) @ManyToOne(fetch=FetchType.LAZY)
should work just fine. Are you sure it's not being overwritten in the query itself? It's possible to specify join fetch
in HQL and / or explicitly set fetch mode via Criteria API which would take precedence over class annotation. If that's not the case and you're still having problems, please post your classes, query and resulting SQL for more to-the-point conversation.
B) @OneToOne
is trickier. If it's definitely not nullable, go with Rob H.'s suggestion and specify it as such:
@OneToOne(optional = false, fetch = FetchType.LAZY)
Otherwise, if you can change your database (add a foreign key column to owner table), do so and map it as "joined":
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
public OtherEntity getOther()
and in OtherEntity:
@OneToOne(mappedBy = "other")
public OwnerEntity getOwner()
If you can't do that (and can't live with eager fetching) bytecode instrumentation is your only option. I have to agree with CPerkins, however - if you have 80!!! joins due to eager OneToOne associations, you've got bigger problems then this :-)
Best Answer
Use property access strategy
Instead of
Use
Now it works fine!
A proxy is initialized if you call any method that is not the identifier getter method. But it just works when using property access strategy. Keep it in mind.
See: Hibernate 5.2 user guide