EclipseLink JPQL (Glassfish v3): join fetch syntax problem? - jpa

With Hibernate I'm used to do something like the following:
select n from NetworkElement n join fetch n.site s where s.active is true
However, EclipseLink complains a lot about this:
Caused by: Exception [EclipseLink-8024] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Syntax error parsing the query [select n from NetworkElement n join fetch n.site s], line 1, column 49: syntax error at [s].
(The query on the stack is different from the one above, but the result is the same)
I've tried different combinations, none of which worked:
select n from NetworkElement n join fetch n.site where n.site.active is true
select n from NetworkElement n join fetch n.site as site where site.active is true
I also tried switching to a different entity in my domain model, suspecting that maybe my mapping is not correct. Still, the same problem.
Could it be that I can only achieve this using a query hint? I don't want to do that.
By the way, I'm using EcliseLink as shipped with Netbeans 6.8 and Glassfish v3.
I'd appreciate any help!
Rodrigo

The main issue is that the JPQL syntax does not allow for aliasing fetch joins and that is why EclipseLink uses query hints for this functionality. There is an Enhancement Request to add aliasing join fetches directly in the JPQL and if you would like to see it completed please vote for it. ( https://bugs.eclipse.org/bugs/show_bug.cgi?id=293775 ).
--Gordon Yorke

Well, it seems that one is not allowed to alias a fetch join in JPQL, indeed.. It works with Hibernate because it supports aliasing through HQL, and you are allowed to issue HQL to a JPA Query object.
Therefore, I had no choice but to switch to named queries with query hints. I don't really like declaring queries with annotations because of the high verbosity on the entity classes, so I added a orm.xml file to the persistence unit's jar, and did the following:
<!-- Fetch network elements -->
<named-query name="fetchNetworkElements">
<query>select n from NetworkElement n</query>
<lock-mode>NONE</lock-mode>
<hint name="eclipselink.join-fetch" value="n.site" />
<hint name="eclipselink.join-fetch" value="n.site.area" />
</named-query>
Hope this gives some clue to anybody struggling with the same shortcomings of the raw JPQL.

Related

Faster/efficient alternative to IN clause in custom/native queries in spring data jpa

I have a custom query along these lines. I get the list of orderIds from outside. I have the entire order object list with me, so I can change the query in any way, if needed.
#Query("SELECT p FROM Person p INNER JOIN p.orders o WHERE o.orderId in :orderIds)")
public List<Person> findByOrderIds(#Param("orderIds") List<String> orderIds);
This query works fine, but sometimes it may have anywhere between 50-1000 entries in the orderIds list sent from outside function. So it becomes very slow, taking as much as 5-6 seconds which is not fast enough. My question is, is there a better, faster way to do this? When I googled, and on this site, I see we can use ANY, EXISTS: Postgresql: alternative to WHERE IN respective WHERE NOT IN or create a temporary table: https://dba.stackexchange.com/questions/12607/ways-to-speed-up-in-queries-under-postgresql or join this to VALUES clause: Alternative when IN clause is inputed A LOT of values (postgreSQL). All these answers are tailored towards direct SQL calls, nothing based on JPA. ANY keyword is not supported by spring-data. Not sure about creating temporary tables in custom queries. I think I can do it with native queries, but have not tried it. I am using spring-data + OpenJPA + PostgresSQL.
Can you please suggest a solution or give pointers? I apologize if I missed anything.
thanks,
Alice
You can use WHERE EXISTS instead of IN Clause in a native SQL Query as well as in HQL in JPA which results in a lot of performance benefits. Please see sample below
Sample JPA Query:
SELECT emp FROM Employee emp JOIN emp.projects p where NOT EXISTS (SELECT project from Project project where p = project AND project.status <> 'Active')

Spring CRUD repository: is there findOneByMaxXYZColumn()?

My requirement:
fetch ONE object (e.g RetainInfo ) from table RETAIN_INFO if VERSION column has max value
Does CRUD repository support for an interface method like
findOneByMaxRetVersionAndCountry("DEFAULT")
Equivalent db2 sql:
select RET_ID, max(ri.RET_VERSION) from RETAIN_INFO ri where ri. COUNTRY='DEFAULT' group by RET_ID fetch first 1 rows only;
This query selects an ID, but I would actually want the RetainInfo object corresponding the SINGLE row returned by the query.
I prefer to get that without using custom query, i.e using findBy or some other method/interface supported by Spring CRUD.
You could use limiting in combination with sorting (spring data reference:limit query results). Declare a method similar to the following in your CrudRepository interface :
RetainInfo findTopByCountryOrderByRetVersionDesc(String country);
You can also use findFirst to get the first result. Before getting the result, make sure to use Orderby and then the ascending(Asc) or descending(Desc). As an example if you want to order by version and retrieve based on productName
RetainInfo findFirstByProductNameOrderByVersionDesc(String productName);
Spring Data doesn't provide an expression to select a max value. All supported query parts could be found in the Spring 1.2.0.RELEASE docs: Appendix A. Namespace reference or line 182 of org.springframework.data.repository.query.parser.Part.
Also feel free to create a feature request at Spring's Jira page.

JPQL equivalent of SQL query using unions and selecting constants

I've written a SQL query that basically selects from a number of tables to determine which ones have rows that were created since a particular date. My SQL looks something like this:
SELECT widget_type FROM(
SELECT 'A' as widget_type
FROM widget_a
WHERE creation_timestamp > :cutoff
UNION
SELECT 'B' as widget_type
FROM widget_b
WHERE creation_timestamp > :cutoff
) types
GROUP BY widget_type
HAVING count(*)>0
That works well in SQL but I recently found that, while JPA may use unions to perform "table per class" polymorphic queries, JPQL does not support unions in queries. So that leaves me wondering whether JPA has an alternative I could use to accomplish the same thing.
In reality, I would be querying against a dozen tables, not just two, so I would like to avoid doing separate queries. I would also like to avoid doing a native SQL query for portability reasons.
In the question I linked to above, it was asked whether the entities that map to widget_a and widget_b are part of the same inheritance tree. Yes, they are. However, if I selected from their base class, I don't believe I would have a way of specifying different string constants for the different child entities, would I? If I could select an entity's class name instead of a string I provide, that might serve my purpose too. But I don't know if that's possible either. Thoughts?
I did a little more searching and found a (seemingly obscure) feature of JPA that serves my purpose perfectly. What I found is that JPA 2 has a type keyword that allows you to limit polymorphic queries to a particular subclass, like so:
SELECT widget
FROM BaseWidget widget
WHERE TYPE(widget) in (WidgetB, WidgetC)
I've found that JPA (or at least Hibernate as a JPA implementation) allows you to use type not only in constraints but also in select lists. This is approximately what my query ended up looking like:
SELECT DISTINCT TYPE(widget)
FROM BaseWidget widget
WHERE widget.creationTimestamp > :cutoff
That query returns a list of Class objects. My original query was selecting string literals because that's closest to what I might have done in SQL. Selecting Class is actually preferable in my case. But if I did prefer to select a constant based on an entity's type, that is the exact scenario that Oracle's documentation uses to illustrate case statements:
SELECT p.name
CASE TYPE(p)
WHEN Student THEN 'kid'
WHEN Guardian THEN 'adult'
WHEN Staff THEN 'adult'
ELSE 'unknown'
END
FROM Person p
Some JPA providers do support UNION,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#UNION
but your query seems very complex, and non object-oriented, so using a native SQL query would probably be best.

Struggling with Lambda expression (VB .net)

I have a relatively simple thing that I can do easily in SQL, but I'm trying to get used to using Lambda expressions, and having a hard time.
Here is a simple example. Basically I have 2 tables.
tblAction (ActionID, ActionName)
tblAudit (AuditID, ActionID, Deleted)
tblAudit may have an entry regarding tblAction with the Deleted flag set to 1.
All I want to do is select actions where we don't have a Deleted entry in tblAudit. So the SQL statement is:
Select tblAction.*
From tblAction LEFT JOIN tblAudit on tblAction.ActionID=tblAudit.ActionID
where tblAudit.Deleted <> 1
What would be the equivalent of the above in VB.Net's LINQ? I tried:
Context.Actions.Where(Function(act) Context.Audit
.Where(Function(aud) aud.Deleted=False AndAlso aud.ActionID=act.ActionID)).ToList
But that is really an inner join type scenario where it requires that each entry in tblAction also has an Entry in tblAudit. I am using Entity Framework Code First to do the database mapping. Is there a way to define the mapping in a way where you can do this?
You should add
Public Property Audits As DbSet<Audit>
into your action entity class (to register the association between those tables).
Now you can just write what you mean:
(From act in Context.Actions Where Not act.Audits.Any(Function(audit) audit.Deleted)).ToArray
which is equivalent to
Context.Actions.Where(Function(act) Not act.Audits.Any(Function(audit) audit.Deleted)).ToArray
and let the LINQ parser do the hard SQL work.

How to build a select using Zend with a DISTINCT specific column?

I'm using Zend Framework for my website and I'd like to retrieve some data from my PostgreSQL database.
I have a request like :
SELECT DISTINCT ON(e.id) e.*, f.*, g.* FROM e, f, g
WHERE e.id = f.id_e AND f.id = g.id_f
This request works well but I don't know how to convert the DISTINCT ON(e.id) with Zend.
It seems that I can get DISTINCT rows but no distinct columns.
$select->distinct()->from("e")->join("f", "e.id = f.id_e")
->join("g", "f.id = g.id_f");
Any idea on how to make a select with distinct column ?
Thanks for help
You probably can't do this with Zend Framework since distinct on is not part of the SQL standard (end of page in Postgres documentation). Although Postgres supports it, I would assume its not part of Zend Framework because you could in theory configure another database connection which does not offer support.
If you know in advance that you're developing for a specific database (Postgres in this case), you could use manually written statements instead. You'll gain more flexibility within the queries and better performance at the cost of no longer being able to switch databases.
You would then instantiate a Zend_Db_Apdapter for Postgres. There a various methods available to get results for SQL queries which are described in the frameworks documentation starting at section Reading Query Results. If you choose to go this route I'd recommend to create an own subclass of the Zend_Db_Adapter_Pgsql class. This is to be able to convert data types and throw exceptions in case of errors instead of returning ambiguous null values and hiding error causes.