SELECT e From Employee e -- why a redundant "e"? - java

Sample query:
SELECT e FROM Employee e WHERE SUBSTRING(e.name, 3) = 'Mac'
In this syntax, it seems intuitive to say SELECT e, that e is now declared or defined(?). However, isn't the second e: FROM Employee e redundant?
This is a throwback or similarity to SQL SELECT syntax?

The second e is a identification variable. It actually defines e by telling the JPQL parser that you are using e somewhere else in your query, and that it refers to the Employee entity. The first occurrence of e is where you usa that e.
So, it's not redundant. If you leave out the first one, the JPQL parser doesn't know what to select. If you leave it out the second time, you're selecting something that the JPQL parser doesn't know.

JPQL syntax is a little different with normal SQL syntax.According to your sample,first e is represent * of normal SQL. So it is not redundant. But you use JPA 2.x, using criteria query is more better than JPQL

I came to this question with the same concerns as you are. I noticed that when you select * the results comes in columns, and when you select e there's only one column with some kind of serialized entities as results. So I found a pretty good explanation about this at http://www.thejavageek.com/2014/03/17/jpa-select-clause/
SELECT e FROM Employee e
This is quite similar to SQL, the difference is:
This query does not return a set of records from columns, instead it
returns an entity.
This entity is aliased to e , it is called as
identification variable.
This identification variable is tied to
Employee type and it means result will be an entity of Employee
type.

IMO there is no need to use the second e in this case (yes it is redundant) if you have single query like this. It makes sense when you join two tables and if those two tables have common column names then you would select each column using that table alias 'e'

use "e." (which columns you have)
SELECT e.name, e.e FROM Employee e WHERE SUBSTRING(e.name, 3) = 'Mac'

DISCLAIMER: This only works with Hibernate as JPA implementation since this information corresponds to HQL.
In this simple case you don't have to use the e (which is nothing more than an alias). Since you are selecting the complete entity, you even don't have to write the select e part. So you can write:
FROM Employee WHERE SUBSTRING(name, 3) = 'Mac'
Explanation:
In the from part, you specify for which Entities you are looking for. The e behind the Employee is just an alias for Employee which you can use to address the whole object (the select part) or attributes from it. In simple queries you don't need it, but as soon you have a join in your query, it's always a good idea to use an alias.
The select part of the query is for selecting which attributes of an entity you want to get back. If you omit the ´selectpart or just specify the alias (e` in this case), JPA gives back the whole Entity. In SQL this does usually not work (at least for Oracle).
To answer your question in the comment: You can use the alias e in the select part of the query. But in Order to do so, you must teach JPA what this e refers to. And this is what the from Employee e part is doing.

Related

Java Entity Object of Union Query

I am attempting to create a domain/entity class based on a complex query. The query unions a bunch of tables together and unfortunately I am not able to create a view on the database for this query. I have been trying to set up the entity object but I am unsure of how to ensure that the marshaling works properly (and ensure the entity acts as read-only object).
As an example of the query, I am doing something like this:
Select
U_T.a,
U_T.b,
U_T.c,
C_T.a
FROM
(select
A_T.a,
null as b,
A_T.c,
1 as ind
from A_T
UNION
select
B_T.a,
B_T.b,
null,
0 as ind
FROM B_T
) U_T
left outer join C_T on C_T.fk_a = U_T.a;
The other issues are that this union can result in instances where there is no unique key column. This is fine as this data is for viewing only, and never editing. However the #Entity annotation wants a column to be listed with the #ID annotation. Another issue is that I do not believe I can use the other entity classes as the goal is to reduce the number of DB transactions from this query (as the actual one can result in hundreds of recursive queries being performed).
If I need to give any more information please let me know.

JPA select rows with where clause

I know that entityManager.find() method can be used to fetch a row with the primary key.
But I have a requirement to define a common find method which accepts a map having the where clause conditions. In the map, key will be the column name and value will be the column name value of the where clause. This method should return the list of selected rows.
Can some one help me out?
Take a look at: EntityManager.createQuery. If I understand your question correctly, this will allow you to create the query that you would like to execute. You could also, take a look at using a CriteriaBuilder.
find fetches the row respect to the primary key.Now as you want
"common find method which accepts a map having the where clause conditions. In the map, key will be the column name and value will be the column name value of the where clause. This method should return the list of selected rows"
for this you have to go for CriteriaQuery like this :
The following simple Criteria query returns all instances of the Pet entity in the data source:
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> allPets = q.getResultList();
The equivalent JPQL query is:
SELECT p FROM Pet p
Moreover i will advise you to go for annotation based mapping in your entities & look for setter & getter for the methods.In that design also you can have customized method by java logic for this go here to read.
Following might be overkill, but is a fairly generic way to approach it utilizing the criteriaBuilder. While I can't paste the code here (work) I created an abstract BaseFilter<Entity> class.
The easy part is then having the implementing objects provide getXX, setXX properties. A getPredicates() was then added to return an ArrayList of predicates that the abstract BaseDAO could then invoke to perform the query.
We worked specifically with the getXX and setXXX so we could reference the elements via eg, get(Entity1_.childObject).get(ChildObject_.grandChildObject) to assist in refactoring. JPA also supports it via string name so you could implement the getPredicates with that.
JPA requires the actual Entity.class reference in their calls it was a bit of fun trying to obtain it. Eventually a google search turned it up.

A set of questions on Hibernate quering

Please help me with these Hibernate querying issues.
Consider the following structure:
#Entity
class Manager {
#OneToMany
List<Project> projects;
}
0) there are 2 possible ways of dynamic fetching in HQL:
select m from Manager m join m.projects
from Manager m join fetch m.projects
In my setup second one always returns a result of cartesian product with wrong number of objects in a list, while the first one always returns correct number of entities in a list. But the sql queries look the same. Does this mean that "select" clause removes redundant objects from the list in-memory? In this case its strange to see an advice in a book to use select distinct ... to get rid of redundant entities, while "select" does the job. If this is a wrong assumption than why these 2 queries return different results?
If I utilize dynamic fetching by one of the 2 methods above I see a classic n+1 select problem output in my hibernate SQL log. Indeed, FetchMode annotations (subselect or join) do not have power while fetching dynamically. Do I really can't solve the n+1 problem in this particular case?
Looks like Hibernate Criteria API does not support generics. Am I right? Looks like I have to use JPA Criteria API instead?
Is it possible to write HQL query with an entity name parameter inside? For example "from :myEntityParam p where p.id=1" and call setParameter("myEntityParam", MyClass.class) after this. Actually what I want is generic HQL query to replace multiple non-generic dao's by one generic one.
0) I always use a select clause, because it allows telling what you want to select, and is mandatory in JPQL anyway. If you want to select the managers with their projects, use
select distinct m from Manager m left join fetch m.projects
If you don't use the distinct keyword, the list will contain n instances of each manager (n being the number of projects of the manager): Hibernate returns as many elements as there are rows in the result set.
1) If you want to avoid the n + 1 problem, fetch the other association in the same query:
select distinct m from Manager m
left join fetch m.projects
left join fetch m.boss
You may also configure batch fetching to load 10 bosses (for example) at a time when the first boss is accessed. Search for "batch fetching" in the reference doc.
2) The whole Hibernate API is not generified. It's been made on JDK 1.4, before generics. That doesn't mean it isn't useful.
3) No. HQL query parameters are, in the end, prepared statement parameters. You must use String concatenation to do this.

Recursive JPA query?

Does JPA 2 have any mechanism for running recursive queries?
Here's my situation: I have an entity E, which contains an integer field x. It also may have children of type E, mapped via #OneToMany. What I'd like to do is find an E by primary key, and get its value of x, along with the x values of all its descendants. Is there any way to do this in a single query?
I'm using Hibernate 3.5.3, but I'd prefer not to have any explicit dependencies on Hibernate APIs.
EDIT: According to this item, Hibernate does not have this feature, or at least it didn't in March. So it seems unlikely that JPA would have it, but I'd like to make sure.
Using the simple Adjacency Model where each row contains a reference to its parents which will refer to another row in same table doesn't co-operate well with JPA. This is because JPA doesn't have support for generating queries using the Oracle CONNECT BY clause or the SQL standard WITH statement. Without either of those 2 clauses its not really possible to make the Adjacency Model useful.
However, there are a couple of other approaches to modelling this problem that can applied to this problem. The first is the Materialised Path Model. This is where the full path to the node is flattened into a single column. The table definition is extended like so:
CREATE TABLE node (id INTEGER,
path VARCHAR,
parent_id INTEGER REFERENCES node(id));
To insert a tree of nodes looks some thing like:
INSERT INTO node VALUES (1, '1', NULL); -- Root Node
INSERT INTO node VALUES (2, '1.2', 1); -- 1st Child of '1'
INSERT INTO node VALUES (3, '1.3', 1); -- 2nd Child of '1'
INSERT INTO node VALUES (4, '1.3.4', 3); -- Child of '3'
So to get Node '1' and all of its children the query is:
SELECT * FROM node WHERE id = 1 OR path LIKE '1.%';
To map this to JPA just make the 'path' column an attribute of your persistent object. You will however have to do the book-keeping to keep the 'path' field up to date. JPA/Hibernate won't do this for you. E.g. if you move the node to a different parent you will have to update both the parent reference and determine the new path value from the new parent object.
The other approach is called the Nested Set Model, which is bit more complex. Probably best described by its originator (rather than added verbatim by me).
There is a third approach called Nested Interval Model, however this has a heavy reliance of stored procedures to implement.
A much more complete explanation to this problem is described in chapter 7 of The Art of SQL.
The best answer in this post seems like a massive work-around hack to me. I've already had to deal with data models where brilliant engineers decided it would be a good Idea to code Tree Hiarchies in DB fields as text such as: "Europe|Uk|Shop1|John" and with massive volumes of data in these tables. Not surprsingly, the performance of query of the form MyHackedTreeField LIKE 'parentHierharchy%' where killers.
Addressing this type of problem ultimately required creating In memory cache of the tree hiearchies and so many others...
If you need to run a recursive query and your data volume is not massive... make your life simple and simply load the DB fields you need to run your plan. And code your recursion in java.
Don't make it in the DB unless you have a good reason to do it.
And even if the volume of data you have is massive, you most likely can subdivide your problem into indepent recursive tree batches and process those one at time without needing to load all the data at once.
I know this question is old, but as it was linked in a different question, I wanted to give an update on this, as Blaze-Persistence offers support for working with recursive CTEs on top of the JPA model.
Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. To model CTEs or recursive CTEs, which is what you need here, you first need to introduce a CTE entity that models the result type of the CTE.
#CTE
#Entity
public class GroupCTE {
#Id Integer id;
}
A query that fetches a hierarchy of groups could look like the following
List<Group> groups = criteriaBuilderFactory.create(entityManager, Group.class)
.withRecursive(GroupCTE.class)
.from(Group.class, "g1")
.bind("id").select("g1.id")
.where("g1.parent").isNull()
.unionAll()
.from(Group.class, "g2")
.innerJoinOn(GroupCTE.class, "cte")
.on("cte.id").eq("g2.parent.id")
.end()
.bind("id").select("g2.id")
.end()
.from(Group.class, "g")
.fetch("groups")
.where("g.id").in()
.from(GroupCTE.class, "c")
.select("c.id")
.end()
.getResultList();
This renders to SQL looking like the following
WITH RECURSIVE GroupCTE(id) AS (
SELECT g1.id
FROM Group g1
WHERE g1.parent_group_id IS NULL
UNION ALL
SELECT g2.id
FROM Group g2
INNER JOIN GroupCTE cte ON g2.parent_group_id = cte.id
)
SELECT *
FROM Group g
LEFT JOIN Group gsub ON gsub.parent_group_id = g.id
WHERE g.id IN (
SELECT c.id
FROM GroupCTE c
)
You can find out more about recursive CTEs in the documentation: https://persistence.blazebit.com/documentation/core/manual/en_US/index.html#recursive-ctes
I had problem like this, querying a menu nodes from one table,
The way I founded was this:
suppose we have a class named Node,created a Unidirectional One-to-Many Association like this:
#OneToMany( fetch = FetchType.EAGER)
#JoinColumn(name = "parent_id", referencedColumnName = "id")
private List<Node> subNodeList;
also have a filed named for example boolean isRoot in entity, to mention if this node is root menu item ,
and then, by querying for nodes that there isRoot is true, we just get top nodes and because of FetchType.EAGER, we also get sub nodes in List.
This will cause multiple queries , but for small menu like things it will be ok.

Select nvl(max(c.EmployeeId),0) in JPQL?

I'm using oracle10g database and eclipselink, I need to obtain the last inserted key from the table so i've created this query
javax.persistence.Query q =
em.createQuery("SELECT nvl(MAX(c.myAtt),0) " +
"from myTable as c");
return Integer.parseInt(q.getSingleResult().toString()); `
But when the table is empy(sometimes it might get empty)
i'm getting ILEGAL ARGUMENT EXCEPTION, cause: JPQL Exception, detail: "An exception occurred while creating a query in EntityManager". What i'm doing wrong?
In the meanwhile somebody else could have inserted something in Autorizaciones and then you receive the wrong id
NVL() is supported now in newer versions of jpql
You could use the COALESCE function. It can be used to achieve the same as nvl. For instance:
select nvl(columna,'1') from table
select COALESCE(columna,'1') from table
Paraphrasing Apu, "I don't know what part of that question to correct first" :-)
First of all, retrieving last inserted key in this way is a VERY BAD THING © It's dangerous, inefficient and most of all, unnecessary as your JPA already does it for you: once you insert your entity, its identifier property will automatically be updated to contain its primary key.
Secondly, as far as your query goes, "myTable" is not something you would use in JPQL, you need to specify your entity name instead (e.g. if you're mapping "Car" to "CAR_TABLE" you should use "Car" instead of "CAR_TABLE" in JPQL queries).
Finally, NVL() is not supported by JPQL. It is supported (sort of, via Expression.ifNull()) by EclipseLink Expressions. Not that you'd need it in a scenario like this, anyway.

Categories