[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [eclipselink-users] Number of problems with query hint extensions
|
Hello,
guess what I fall over while trying to understand the JPA 2 Spec, Chapter 6.5.4:
"Multiple levels of fetch joins are not required to be supported by an implementation of this
specification. Applications that use multi-level fetch joins will not be portable."
I don't understand at all, why this restriction is made in the specification.
Does anyone know this?
Does EclipseLink implement the "multi-level fetch joins"?
We absolutely need "multi-level fetch joins". So if EL does not support them, there's no sense
in migrating to JPA 2.0.
Kind Regards, Michael
Tom Ware schrieb:
> Hi Michael,
>
> I just realized there is another JPA-based way you can do this. I
> believe the JPA 2.0 criteria API allows nested fetch joins in a way that
> could allow this to work as well. (EclipseLink 2.0 or better) I don't
> have a good documentation link aside from the specification itself, but
> here's a chunk of code from our tests that does a fetch.
>
> CriteriaBuilder qb = em.getCriteriaBuilder();
> CriteriaQuery<Employee> cq = qb.createQuery(Employee.class);
> Root<Employee> root = cq.from(Employee.class);
> root.fetch("phoneNumbers", JoinType.LEFT);
> List result = em.createQuery(cq).getResultList();
>
> I think that playing around with the fetch API should allow you to get
> the query you want.
>
> For native code, here is a sample using a slightly different Object
> model. Customer has a 1-M to Order and Order has a 1-1 to salesPerson.
>
> Start with this:
>
> EntityManager em = createEntityManager();
> Query query = em.createQuery("select c from Customer c");
>
> The following replicates your issue:
>
> query.setHint(QueryHints.FETCH, "c.orders");
> query.setHint(QueryHints.FETCH, "o.orders.salesPerson");
> List results = query.getResultList();
>
> The follow native API avoids it:
>
> // get the underlying Eclipse query
> ReadAllQuery raq =
> (ReadAllQuery)((JpaQuery)query).getDatabaseQuery();
>
> // get the EclipseLink ExpressionBuilder for the query
> ExpressionBuilder customerBuilder = raq.getExpressionBuilder();
>
> // build an expression to get the orders
> // orders is 1-m so use anyOf() for join or anyOfAllowingNull() for
> outer join
> Expression ordersExp = customerBuilder.anyOf("orders");
>
> // build an expression for salesPerson using the already-created
> // ordersExp to indicate to use the same join
> // use get() because this is a 1-1 or getAllowingNull() for outer join
> Expression salesPersonExp = ordersExp.get("salesPerson");
>
> // fetch join these two attributes
> raq.addJoinedAttribute(ordersExp);
> raq.addJoinedAttribute(salesPersonExp);
>
> // back to standard JPA
> List results = query.getResultList();
>
> There is some documentation here:
>
> http://wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29#How_to_Use_EclipseLink_Query_API_in_JPA_Queries
>
>
> -Tom
>
> Michael Simons wrote:
>> Hello Tom,
>>
>> I've tried the possibility mentioned by Andrei, but that seems to slow
>> because of the
>> unnecessary outer-joins. So it only works for QueryHints.FETCH.
>> So the Native EclipseLink API definitely is an option for us. Can You
>> please tell where to get
>> information about it.
>>
>> Kind Regards, Michael
>>
>>
>> Tom Ware schrieb:
>>> Hi Michael,
>>>
>>> The problem here is that each of your hints is being treated as
>>> individual.
>>>
>>> i.e.
>>> x.locatedVehicles causes one fetch and x.locatedVehicles.tours causes a
>>> completely independent fetch and so on. There is probably something we
>>> could do here to enhance the framework to allow expressions like
>>> x.locatedVehicles and x.locatedVehicles.tours to refer to the same
>>> thing. (maybe some kind of aliasing strategy like JPQL uses for its
>>> non-fetch joins) Please feel free to enter an enhancement.
>>>
>>> To workaround, the only thing I can think of is to use Native
>>> EclipseLink API. Let me know if that is an option for you and I can
>>> help out.
>>>
>>> As for batching, that works a little differently, you should not see
>>> any SQL related to the batch on your original query, but when you
>>> traverse the relationship that is batched, you will get all the objects
>>> on the other side of the relationship as a batch.
>>>
>>> -Tom
>>>
>>> Michael Simons wrote:
>>>> Hello once more,
>>>>
>>>> when I expand the query to also get the stops within a tour like this:
>>>> query = em.createQuery("SELECT DISTINCT x FROM Depot x WHERE
>>>> x.scenario = :currentScenario");
>>>> query.setHint (QueryHints.FETCH, "x.locatedVehicles");
>>>> query.setHint (QueryHints.FETCH, "x.locatedVehicles.tours");
>>>> query.setHint (QueryHints.FETCH, "x.locatedVehicles.tours.positions");
>>>>
>>>> things get even worse, as you can see by the SQL statement below. As
>>>> you might guess that
>>>> statement runs almost for ever.
>>>> That's because the statement is much too complicated, e.g. the vehicle
>>>> is joined three times!
>>>> But that's not necessary at all, it's bloated.
>>>> Why is this done?
>>>>
>>>>
>>>> SELECT DISTINCT t1.depot_id, t1.bot_pump_rate, t1.available, ...
>>>> FROM tour_position t6
>>>> LEFT OUTER JOIN order_stop t7 ON (t7.tour_position_id =
>>>> t6.tour_position_id)
>>>> LEFT OUTER JOIN load_stop t8 ON (t8.tour_position_id =
>>>> t6.tour_position_id), tour t5, vehicle
>>>> t4, tour t3, vehicle t2, depot t1, vehicle t0
>>>> WHERE ((t1.scenario_id = ?)
>>>> AND ((((((t0.depot_id = t1.depot_id) AND (t2.depot_id = t1.depot_id))
>>>> AND (t3.vehicle_id = t2.vehicle_id)) AND (t4.depot_id = t1.depot_id))
>>>> AND (t5.vehicle_id = t4.vehicle_id)) AND (t6.tour_id = t5.tour_id)))
>>>>
>>>> kind Regards, Michael
>>>>
>>>> Michael Simons schrieb:
>>>>> Hello,
>>>>>
>>>>> Given the follwing JPQL Query:
>>>>> "SELECT DISTINCT d FROM Depot d WHERE d.scenario = :currentScenario"
>>>>>
>>>>> with the following classes:
>>>>> @Entity @Table(name="depot") class Depot {
>>>>> ...
>>>>> List<Vehicle> locatedVehicles;
>>>>> }
>>>>>
>>>>> @Entity @Table(name="vehicle") class Vehicle {
>>>>> ...
>>>>> List<Tour> tours;
>>>>> }
>>>>>
>>>>> @Entity @Table(name="tour") class Tour {
>>>>> ...
>>>>> }
>>>>>
>>>>> We want EL to query not only the depots within a given scenario but
>>>>> also all vehicles located at
>>>>> these depots, and all tours driven by theses vehicles (trucks).
>>>>> So, we set the following hints:
>>>>> query.setHint (QueryHints.LEFT_FETCH, "x.locatedVehicles");
>>>>> query.setHint (QueryHints.LEFT_FETCH,
>>>>> "x.locatedVehicles.tours");
>>>>>
>>>>> The following SQL-statement is created by EL:
>>>>> SELECT DISTINCT t1.depot_id, t1..., t0.vehicle_id, t0...,
>>>>> t2.vehicle_id, t2..., t3.tour_id, t3...
>>>>> FROM depot t1
>>>>> LEFT OUTER JOIN vehicle t0 ON (t0.depot_id = t1.depot_id)
>>>>> LEFT OUTER JOIN vehicle t2 ON (t2.depot_id = t1.depot_id)
>>>>> LEFT OUTER JOIN tour t3 ON (t3.vehicle_id = t2.vehicle_id)
>>>>> WHERE (t1.scenario_id = ?)
>>>>>
>>>>> Why is vehicle joined twice?
>>>>>
>>>>> On the other hand, when specifying
>>>>> query.setHint (QueryHints.BATCH, "x.locatedVehicles");
>>>>> query.setHint (QueryHints.BATCH, "x.locatedVehicles.tours");
>>>>>
>>>>> neither vehciles nor tours are selected at all.
>>>>>
>>>>> Is there anything wrong with these hints?
>>>>> Is there a detailed documentation on how to use QueryHints.BATCH /
>>>>> .FETCH / .LEFT_FETCH ?
>>>>>
>>>>> Kind Regards, Michael
>>>>> _______________________________________________
>>>>> eclipselink-users mailing list
>>>>> eclipselink-users@xxxxxxxxxxx
>>>>> https://dev.eclipse.org/mailman/listinfo/eclipselink-users
>>>>>
>>>>
>>>> _______________________________________________
>>>> eclipselink-users mailing list
>>>> eclipselink-users@xxxxxxxxxxx
>>>> https://dev.eclipse.org/mailman/listinfo/eclipselink-users
>>> _______________________________________________
>>> eclipselink-users mailing list
>>> eclipselink-users@xxxxxxxxxxx
>>> https://dev.eclipse.org/mailman/listinfo/eclipselink-users
>>>
>>
>>
>> _______________________________________________
>> eclipselink-users mailing list
>> eclipselink-users@xxxxxxxxxxx
>> https://dev.eclipse.org/mailman/listinfo/eclipselink-users
> _______________________________________________
> eclipselink-users mailing list
> eclipselink-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/eclipselink-users
>