Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] Number of problems with query hint extensions

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


Back to the top