How to force JPA(eclipselink) to use joins instead of independent queries? - jpa

I'm using JPA 2 in my project (eclipselink provider), and I have the following problem:
When I execute the following code:
em.createQuery("select t from " + entityName + " t where t.id = ?1"
).setParameter(1, id)
.setHint(QueryHints.REFRESH, HintValues.TRUE)
.setHint(QueryHints.REFRESH_CASCADE, CascadePolicy.CascadeAllParts)
.getSingleResult();
JPA generates tons of queries to fetch all dependent objects( i.e ~90 queries to fetch an entity).
It there any way to force JPA to use joins instead of independent queries?

You can use join fetching or batch fetching to optimize relationships. Also you should use LAZY on your relationships to avoid loading them when not required.
See,
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html

In your query you can use join and fetch to construct the query yourself.
So for example if your entity t has a
#OneToMany public List<RelatedEntity> things;
then your query can use:
select t from entityName t join fetch t.things where t.id = ?1
Read the documentation for JPQL (Java Persistence Query Language).

Related

Looking for the best option to limit JPA query volume

I have an entity model where I need to dig down two collections to get the data required on the screen - in Hibernate that triggered first an exception when I created a JPA join fetch query until I changed the collections to sets. It is still a cartesian product though. I am trying to write a JPARepository function to execute the following query now, but only with specific fields, because the resulting query returns more than 100 fields of which I need less than 10.
SELECT p FROM Person p
JOIN FETCH p.responsibilities r
JOIN FETCH r.configurations c
JOIN FETCH c.type
WHERE p.id = :id
My JPA Repository method is already using projection interfaces but I think because I am using the #Query annotation it does not optimize the query. When I tried it as a plain, typed findById() method with projection interfaces it did execute a load of subqueries which costs much more time.
Any recommendations

Join multiple table using generic repository patten with Entity framework with unit of work

I am developing a web application using MVC4 with Entity framework 5.
I have created generic repository for accessing database with unit of work.
Having the below two repository,
CustomerRepository - Customer table
LibraryRepository - Library table
These two tables are not linked with each other( there is no foreign key relation ).
Want to write a query by combining these repository. Is possible to write a query by combining two different repository?
If yes, please let me know the way.
If your generic repositories expose an IQueryable method, you should be able to use a LINQ join to query both repositories:
var items = from c in customerRepository.AsQueryable()
join l in libraryRepository.AsQueryable() on c.SomeProperty equals l.SomeOtherProperty
select new { CustomerName = c.FirstName, LibraryName = l.Name };
There may be limitations to what the query can do, but I did a quick proof of concept on my own codebase between two separate repositories and it worked just fine (with the expected sql firing).
Update
It appears you are attempting two separate queries with a where clause-- I don't believe LINQ2Entities supports what you are attempting to do. Try updating your code to the following:
var customer = (
from cus in _customer.Query()
join lib in _library.Query()
on cus.LId equals lib.Id select cus
).ToList();
Where you are replacing the two 'from/where' queries with a 'join/on'.

Limiting size of jpa association query

The following query gets all the employees in the department:
List<Employee> employees = em.find(Department.class,departmentid).getEmployeeList();
However, i am looking to get only a limited number of results from the above query and not complete resultset. Is it possible via the above query?
I am aware of em.createQuery() alternative however would like to use the existing one-to-many association in the entity and not write a new query to get limited results.
Any help or ideas would be great.
Use JPQL,
Select e from Department d join d.employees e where d.id = :id
And set the maxResults on the query

jpa lazy fetch entities over multiple levels with criteria api

I am using JPA2 with it's Criteria API to select my entities from the database. The implementation is OpenJPA on WebSphere Application Server. All my entities are modeled with Fetchtype=Lazy.
I select an entity with some criteria from the database and want to load all nested data from sub-tables at once.
If I have a datamodel where table A is joined oneToMany to table B, I can use a Fetch-clause in my criteria query:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<A> cq = cb.createQuery(A.class);
Root<A> root = cq.from(A.class);
Fetch<A,B> fetch = root.fetch(A_.elementsOfB, JoinType.LEFT);
This works fine. I get an element A and all of its elements of B are filled correctly.
Now table B has a oneToMany-relationship to table C and I want to load them too. So I add the following statement to my query:
Fetch<B,C> fetch2 = fetch.fetch(B_.elementsOfC, JoinType.LEFT);
But this wont do anything.
Does anybody know how to fetch multi level entities in one query?
It does not work with JPQL and there is no way to make it work in CriteriaQueries either. Specification limits fetched entities to the ones in that are referenced directly from the returned entity:
About fetch join with CriteriaQuery:
An association or attribute referenced by the fetch method must be
referenced from an entity or embeddable that is returned as the result
of the query.
About fetch join in JPQL:
The association referenced by the right side of the FETCH JOIN clause
must be an association or ele ment collection that is referenced from
an entity or embeddable that is returned as a result of the query.
Same limitation is also told in OpenJPA documentation.
For what is worth. I do this all the time and it works just fine.
Several points:
I'm using jpa 2.1, but I'm almost sure it used to work in jpa 2.0 as well.
I'm using the criteria api, and I know some things work diferent in jpql. So don't think it works some way or doesn't work because that's what happens in jpql. Most often they do behave in the same way, but not always.
(Also i'm using plain criteria api, no querydsl or anything. Sometimes it makes a difference)
My associations tend to be SINGULAR_ATTRIBUTE. So maybe that's the problem here. Try a test with the joins in reverse "c.fetch(b).fetch(a)" and see if that works. I know it's not the same, but just to see if it gives you any hint. I'm almost sure I have done it with onetomany left fetch joins too, though.
Yep. I just checked and found it: root.fetch("targets", LEFT).fetch("destinations", LEFT).fetch("internal", LEFT)
This has been working without problems for months, maybe more than a year.
I just run a test and it generates this query:
select -- all fields from all tables
...
from agreement a
left outer join target t on a.id = t.agreement_id
left outer join destination d on t.id = d.target_id
left outer join internal i on d.id = i.destination_id
And returns all rows with all associations with all fields.
Maybe the problem is a different thing. You just say "it wont do anyhting". I don't know if it throws an exception or what, but maybe it executes the query properly but doesn't return the rows you expect because of some conditions or something like that.
You could design a view in the DB joining tables b and c, create the entity and fetchit insted of the original entity.

entity framework: join on the rule "A = substring(B)"?

Could I ask somebody show me the way how to declare the association between two entities 'Record' and 'DictionaryItem' if corresponded tables on the DB level are joined by such interesting rule:
FROM Records R LEFT OUTER JOIN DictionaryItems D
ON SUBSTRING(R.CompositeKey,3,8) = D.DictionaryItemId
P.S. I'm now working with POCO entities.
Linq-to-entities doesn't support Substring. You must either execute SQL directly by calling context.Database.SqlQuery<> or you must use Entity SQL - that would probably require converting DbContext to ObjectContext via IObjectContextAdapter, creating ObjectSet and running ESQL query.