In Hibernate when you retrieve an Entity via a load, if you access that Entity's id accessor it does not initialize the proxy:
Property myProp = (Property) session.load(Property.class, myId);
myProp.getId(); // Doesn't load the proxy
myProp.getDescription(); // Loads the proxy from the database hit
However, I am unclear what the rules are for loading association proxies. I was under the impression that when you retrieve an Entity via a HQL query or Criteria the same rules apply.
Each Property
in my code has a Company
. The Company
is declared as such:
@ManyToOne(fetch = FetchType.LAZY, optional=false)
@JoinColumn(name = "company_id", nullable=false)
private Company company;
However, in my code I'm currently getting N+1 selects when iterating through the Properties
because the Company
is being loaded when I call Company.getId()
.
In both the Company
and Property
object the id field is a Long annotated with @Id
.
Is there some other consideration I'm missing in order to prevent the loading of the Company
entity?
Hibernate uses a proxy object to implement lazy loading. When we request to load the Object from the database, and the fetched Object has a reference to another concrete object, Hibernate returns a proxy instead of the concrete associated object.
How hibernate uses proxy pattern: Hibernate uses proxy pattern to lazy load entities. For lazy loaded entity or collection, hibernate defers database hit till any property other than identifier (Property marked with @Id) is accessed. The proxy object which hibernate creates has only identifier value set.
Explanation: load() method returns proxy object. load() method should be used if it is sure that instance exists.
The JPA lazy loading mechanism can either be implemented using Proxies or Bytecode Enhancement so that calls to lazy associations can be intercepted and relationships initialized prior to returning the result back to the caller.
It does not work as expected simply because of you have to use property access instead of field access.
Instead of
@ManyToOne(fetch=FetchType.LAZY, optional=false)
@JoinColumn(name="COMPANY_ID", nullable=false)
private Company company;
Use
@ManyToOne(fetch=FetchType.LAZY, optional=false)
@JoinColumn(name="COMPANY_ID", nullable=false)
public Company getCompany() {
return this.company;
}
Takes care you can not use property access and field acces at the same time. So you should choose one approach.
regards,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With