Eager fetch performs left join in hibernate but fires seperate sql queries in springboot/JPA
The findByCustomerId
will actually generate a query based on that method instead of using em.find
. It will create something along the lines of SELECT c FROM Customer c WHERE c.customerId=:customerId
. afterwards it will notice the fetch strategy and obtain the needed references. This is also explained here. The query will do exactlly what you instruct it to do.
If you want to eagerly load the reference you would need to write the query yourself along the lines of SELECT c FROM Customer c JOIN FETCH c.orders o WHERE c.customerId=:customerId
, this will automatically retrieve the orders.
However the customerId
is actually the primary key or identitifier for your entity and thus you should actually be using the findById
or findOne
method (depending on your Spring Data JPA version). This will use the EntityManager.find
which should take the mapping information into account and create the appropriate query.
JPA & Hibernate: Eager loading performing subsequent queries to fetch all data, instead of doing it in just one query
I found it described in https://vladmihalcea.com/eager-fetching-is-a-code-smell/
under EAGER fetching inconsistencies:
Both JPQL and Criteria queries default to select fetching, therefore issuing a secondary select for each individual EAGER association. The larger the associations’ number, the more additional individual SELECTS, the more it will affect our application performance.
Also, note that Hibernate similarly ignoreg fetching annotations for HQL queries:
https://developer.jboss.org/wiki/HibernateFAQ-AdvancedProblems#jive_content_id_Hibernate_ignores_my_outerjointrue_or_fetchjoin_setting_and_fetches_an_association_lazily_using_n1_selects
Hibernate ignores my outer-join="true" or fetch="join" setting and fetches an association lazily, using n+1 selects!
HQL queries always ignore the setting for outer-join or fetch="join" defined in mapping metadata. This setting applies only to associations fetched using get() or load(), Criteria queries, and graph navigation. If you need to enable eager fetching for a HQL query, use an explicit LEFT JOIN FETCH.
How to perform an EAGER fetch in JPQL
Yup. You are right. The syntax is [inner|left] join fetch
. Example :
select cal from ContactAddressLink cal
inner join fetch cal.contact c
inner join fetch cal.address a
where cal.id = 123456789
If you want to match ContactAddressLink
if it has Contact
/Address
, use inner join fetch
.
If you want to match ContactAddressLink
even if it does not have Contact
/Address
, use left join fetch
.
Eager fetch does not seem to join
Ebean is the underlying JPA implementation
Ebean is not a JPA Implementation. Ebean has a little in common with the JPA standard. It looks a little similar, because it's annotations look similar to JPA's.
Cause of your problem: Ebean does not support fetch=... attribute on @ManyToMany annotation.
2 solutions:
Remove fetch=... from annotation and instead use fetch() method on either the
play.db.ebean.Model.Finder<I,T>
object (which implementscom.avaje.ebean.Query<T>
) or the com.avaje.ebean.Ebean object.Problem is there are two separate persistent libraries here (play.db.ebean and com.avaje.ebean) and integration between them is a challenge and issue.
E.g. play.db.ebean.Model.Finder.fetch() method returnscom.avaje.ebean.Query<T>
rather than play.db.ebean.Model.Finder - which I find unhelpful as it takes you away from the play API Model helper. After calling fetch() apparently you can no longer use the Model.Finder methods - not much of a "helper" class at that point.
To be honest, I don't think the fetch functionality is a first class feature within Play API yet - best to defer to the Avaje API.Two examples of using fetch() from within the Avaje API:
// single SQL query with a fetch join
List<Order> l0 = Ebean.find(Order.class)
.fetch("customer")
.findList();and
// two separate SQL queries
List<Order> l0 = Ebean.find(Order.class)
.fetch("customer", new FetchConfig().query())
.findList();Note: the last release/update to Ebean (other that bug fixes) was 6 Nov 2010 - 2 full years ago. The uptake rate of Ebean is very low.
Switch to using a JPA 2.0 implementation within Play. The 2.0 release of JPA is very powerful indeed, is easy to use, and is very widely supported. It will probably mean the death of Ebean. Note that Play has added the following configuration feature into 2.0 (wasn't present in 1.1) - suggesting Play is moving towards fuller support for JPA from any provider.
http://www.playframework.org/documentation/2.0/JavaJPAOnce you do this, stop using play.db classes and com.avaje classes - I suggest you use 100% javax.persistence classes.
Related Topics
Why Does Arraylist Have "Implements List"
CSV Parsing in Java - Working Example
Drawing a Simple Line Graph in Java
Why Can't a Generic Type Parameter Have a Lower Bound in Java
How to Validate an Xml File Using Java with an Xsd Having an Include
How to Convert String to Date Without Knowing the Format
Retrieving a Random Item from Arraylist
Eclipse Error: "Failed to Connect to Remote Vm"
Why Does Eclipse Complain About @Override on Interface Methods
The Server Time Zone Value 'Aest' Is Unrecognized or Represents More Than One Time Zone
Spark SQL How to Explode Without Losing Null Values
Invalid Thread Access Error with Java Swt
How to Generate Cdata Block Using Jaxb
How to Convert Binary String Value to Decimal
Shortcut "Or-Assignment" (|=) Operator in Java
How to Solve the Lazyinitializationexception When Using JPA and Hibernate