JPQl Am new in jpa and I want to query all fields from two entities and then use the entity classes getters to access the data .
Query q = em.createQuery("SELECT u(*),f(*) FROM User u join Employee f in u.empid=f.id WHERE u.username = :login AND u.passowrd = :pass");
q.setParameter("login", usernameTextField.getText().trim());
q.setParameter("pass", passwordPasswordField.getText().trim());
Error
Exception [EclipseLink-0] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b):
org.eclipse.persistence.exceptions.JPQLException
Exception Description: Syntax error parsing [SELECT u(),f() FROM User u join Employee f in u.empid=f.id WHERE u.username = :login AND u.passowrd = :pass].
[9, 9] The left expression is missing from the arithmetic expression.
[10, 10] The right expression is missing from the arithmetic expression.
[15, 15] The left expression is missing from the arithmetic expression.
[16, 16] The right expression is missing from the arithmetic expression.
[7, 8] The SELECT clause has 'u' and '()' that are not separated by a comma.
[13, 14] The SELECT clause has 'f' and '()' that are not separated by a comma.
[56, 57] The FROM clause has 'User u JOIN Employee f IN u.empid=' and 'f.id ' that are not separated by a comma.
[46, 57] The expression is invalid, which means it does not follow the JPQL grammar.
[62, 62] An identification variable must be provided for a range variable declaration.
Thank you all for your contributions......so far I have amended the query up to this
SELECT u,f
FROM User u, Employee f
WHERE u.username = :login AND u.passowrd = :pass AND u.empid=f.id
and now I am getting this error
internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.id))' at line 1
Error Code: 1064
Call: SELECT t0.id, t0.level, t0.passowrd, t0.username, t0.empid, t1.id, t1.address, t1.email, t1.gender, t1.idnum, t1.name, t1.phone, t1.staffcol, t1.dept FROM user t0, staff t1 WHERE (((t0.username = ?) AND (t0.passowrd = ?)) AND (t0.empid = t1.id.t1.id))
bind => [2 parameters bound]
Query: ReportQuery(referenceClass=User sql="SELECT t0.id, t0.level, t0.passowrd, t0.username, t0.empid, t1.id, t1.address, t1.email, t1.gender, t1.idnum, t1.name, t1.phone, t1.staffcol, t1.dept FROM user t0, staff t1 WHERE (((t0.username = ?) AND (t0.passowrd = ?)) AND (t0.empid = t1.id.t1.id))")
Question already asked:
JPA: Query that returns multiple entities
(In this example it's hibernate what is an implementation von jpa)
Maybe something like this:
Query q = em.createQuery("SELECT u, f FROM User u, Employee f WHERE u.empid = f.id and u.username = :login AND u.passowrd = :pass");
q.setParameter("login", usernameTextField.getText().trim());
q.setParameter("pass", passwordPasswordField.getText().trim());
Object[] result = (Object[]) q.getSingleResult();
User user = result[0];
Employee emp = result[1];
edit: This part of your translated query looks like you have a mapping problem in your Employee class:
... t1.id.t1.id ...
I think you can't do such a thing and here is why.
The query you post is "inspired" by the relational approach, i.e. you query for a table with arbitrary fields (maybe produced by the join and maybe even artificial).
JPA is by nature is an ORM framework - which means it encapsulates a relation structure by wrapping it in Object.
So, you have to work with Objects as its common in relational data world.
This means that you always should query for an object.
Now how about the join you've mentioned?
Actually join is a way to get a projection in relational data modeling world, again its not for object oriented world, here we operate with inheritance and composition.
You may model the same relation with these mentioned above.
So in object based data modeling world you should think about the "relation" between user and employee as like these are objects and not different tables - think as a object oriented language programmer and not an sql user.
In this particular case my first bet would be saying that a user 'is an' employee with some additional information (I might be wrong its more a question of data modeling, it might be an opposite, so you should think about this).
So you define class Employee in java
then you define class User in java:
class Employee {
}
class User extends Employee {
}
And then you provide a relational mapping to this hierarchy of objects.
There are 3 different strategies for mapping such a thing, you might be interesting on reading this
Hope this helps
I am not expert but I assume:
Make your return type main entity like following.
public User methodWhichReturnsListAfterQuery(){
Query q = em.createQuery("SELECT u FROM User u join u.employee f WHERE u.empid=f.id AND u.username = :login AND u.passowrd = :pass");
q.setParameter("login", usernameTextField.getText().trim());
q.setParameter("pass", passwordPasswordField.getText().trim());
return (User)query.getSingleResult();
}
I assume your main entity is User
Your User entity like following:
public class User Implements Serializable{
.
.
//Some relation type
private Employee employee;
.
.
//getter() and setter()
}
get values after query
User user= methodWhichReturnsListAfterQuery ();
Now you can get values like this:
String userName=user.getUserName();
String password=user.getPassword();
String name=user.getEmployee().getName();
Long departMentId=user.getEmoloyee().getDepartmentId();
Hope you get...
Related
I am using Spring Boot, Groovy and JPA/Hibernate to migrate an old application. The only restriction is that the database model must not be changed and I found myself with a weird situation in which a OneOnOne relationship:
Please look at the following model setup:
#Entity
#Table(name='table1')
class Table1 {
#Id
Table1Id id
#Column(name='sequence_num')
Integer seqNum
#Column(name='item_source')
String itemSource
#Column(name='source_type')
String sourceType
#OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name='key_field_2', insertable=false, updatable=false)
#NotFound(action=NotFoundAction.IGNORE)
// #Fetch(FetchMode.JOIN)
Table2 table2
}
#Embeddable
class Table1Id implements Serializable {
#Column(name='key_field_1')
String key1
#Column(name='key_field_2')
String key2
}
#Entity
#Table(name='table2')
class Table2 {
#Id
#Column(name='key_id')
String keyId
#Column(name='field1')
String field1
#Column(name='field2')
String field2
#Column(name='field3')
String field3
}
My Spock test looks as follows:
def "Try out the JOIN select with Criteria API"() {
given:
CriteriaBuilder cb = entityManager.getCriteriaBuilder()
CriteriaQuery<Object[]> cQuery = cb.createQuery(Object[].class)
Root<Table1> t1 = cQuery.from(Table1.class)
Path<Table2> t2 = t1.get('table2')
Join<Table1, Table2> lanyonLeftJoin = t1.join('table2', JoinType.INNER)
Predicate where = cb.equal(t1.get('itemSource'), 'ABC')
cQuery.multiselect(t1, t2)
cQuery.where(where)
when:
List<Object[]> result = entityManager.createQuery(cQuery).getResultList()
then:
result.each{ aRow ->
println "${aRow[0]}, ${aRow[1]}"
}
}
This configuration successfully generates an INNER JOIN between Table1 and Table2, NOTE that even the constant on the "where" clause is correctly interpreted.
However for some strange reason Table2 gets re-queried for every row returned in the first query.
The output that I see is:
Hibernate:
select
table10_.key_field_1 as key_field_11_3_0_,
table10_.key_field_2 as key_field_22_3_0_,
table21_.key_id as key_id1_5_1_,
table10_.item_source as item_source3_3_0_,
table10_.sequence_num as sequence_num4_3_0_,
table10_.source_type as source_type5_3_0_,
table21_.field2 as field23_5_1_,
table21_.field3 as field34_5_1_,
table21_.field1 as field15_5_1_
from
table1 table10_
inner join
table2 table21_
on table10_.key_field_2=table21_.key_id
where
table10_.item_source=?
Hibernate:
select
table20_.key_id as key_id1_5_0_,
table20_.field2 as field23_5_0_,
table20_.field3 as field34_5_0_,
table20_.field1 as field15_5_0_
from
table2 table20_
where
table20_.key_id=?
Hibernate:
select
table20_.key_id as key_id1_5_0_,
table20_.field2 as field23_5_0_,
table20_.field3 as field34_5_0_,
table20_.field1 as field15_5_0_
from
table2 table20_
where
table20_.key_id=?
// 500+ more of these
As we can see the first query successfully returns all rows from both tables and it is actually the exact query I am looking for. However there is all those unnecessary extra queries being performed.
Is there any reason why JPA would do such thing and is there a way to prevent it??
I have the impression I am missing something very obvious here.
Thanks in advance for your help
Update 1
If I replace
cQuery.multiselect(t1, t2)
for
cQuery.multiselect(t1.get('id').get('key1'), t1.get('id').get('key2'),
t1.get('fieldX'), t1.get('fieldY'), t1.get('fieldZ'),
t2.get('fieldA'), t2.get('fieldB'), t2.get('fieldC') ...)
It generates the exact same inner join query and DOES NOT re-queries Table2 again.
In other words, looks like (at least for this case) I need to explicitly list all the fields from both tables. Not a nice workaround as it can get very ugly very quickly for tables with a lot of fields. I wonder if there is a way to retrieve all the #Column annotated fields/getters without resourcing to a bunch of reflection stuff?
I think I've got it!
#JoinFormula:
Primary Key in Table2 is INT and the field in Table1 that is used as FK is String (I completely missed that! duh!). So, the solution for that was to apply a #JoinFormula instead of a #JoinColumn in the form of:
#OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumnsOrFormulas([
#JoinColumnOrFormula(formula=#JoinFormula(value='CAST(key_field_2 AS INT)'))
])
#NotFound(action=NotFoundAction.IGNORE)
Table2 table2
This strangely returns a List<Object[]> each item of the List contains an array of 2 elements: one instance of Table1 and one instance of Table2.
Join Fetch:
Following your suggestion I added "join fetch" to the query, so it looks like:
select t1, t2 from Table1 t1 **join fetch** t1.table2 t2 where t1.itemSource = 'ABC'
This causes Hibernate to correctly return a List<Table1>
Either with the #JoinFormula alone or the #JoinFormula + "join fetch" hibernate stopped generating the n+1 queries.
Debugging Hibernate code I've found that it correctly retrieves and stores in Session both entities the first time it queries the DB with the join query, however the difference between PK and FK data types causes Hibernate to re-query the DB again, once per each row retrieved in the first query.
I am trying to find the maximum value of a Date column in mySQL DB using hibernate query language with join
#Query("select o.techid, CAST(MAX(o.last_modified) AS DATE)
from com.dw.model.user.User as u
left join com.dw.model.order.Order as o
on u.username=o.techid group by o.techid")
List<User> findUsers();
Model class =
#Entity(name = "orders")
#Scope("prototype")
#Component
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
public class Order {
#Id
private long orderNumber;
private Date last_modified;
I am getting this error :-
Caused by: java.lang.IllegalStateException: DOT node with no left-hand-side!
Can anyone please help me out by telling me how to write this in Hibernate?
Remove your package names. An entity is defined by its name only. Dots are used for properties and links between tables (when defined as a #ManyToOne* property).
select o.techid, CAST(MAX(o.last_modified) AS DATE)
from User as u
left join Order as o
on u.username=o.techid group by o.techid
Think Classes and Properties, not columns, when you write HQL.
Try following solution, this should work
SELECT o.techid, CAST(MAX(o.last_modified) AS DATE)
FROM User u LEFT JOIN u.order o GROUP BY o.techid
I have a simple criteria api query with a (inner) join
public void find(Category category) {
CriteriaBuilder b = getQueryBuilder();
CriteriaQuery<Product> q = createQuery();
Root<Product> root = q.from(Product.class);
Join<Product, Category> myCategory= root.join("category");
q.where(b.equal(myCategory, category));
entityManager.createQuery(q).getResultList();
}
The query works, but if I enable in persistence.xml the sql logging I can see that the query is a
SELECT * FROM product, category WHERE ...
and no
SELECT * FROM product join category on category.id = product.category ...
Any idea what the reason for this is? The where statement is very slow, so a real join would be really better.
I'm using eclipselink 2.5.1, Java EE7 and postgres
I also have a superclass from Product
#Entity
#Audit
public class SuperClass {}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Product extends SuperClass {}
But this should be no problem?
A join is actual being perform, however the SQL used to perform the join is written in implicit join notation. The join will have the same performance as explicit join notation (notation using JOIN and ON). A "real" join is being performed, however it is just not in the explicit join notation (aka ANSI SQL 92) you expect.
You are selecting from Root with Product.class, but you need to select from join.
And I think result of you join must be mapped to some class, containing both entities Product and Category. If you like to get only product from join you can write something like this:
CriteriaBuilder b = getQueryBuilder();
CriteriaQuery<Product> q1 = createQuery();
CriteriaQuery<Product> q2 = createQuery();
Root<Product> root = q1.from(Product.class);
q2.select(root.as(Product.class)).from(root.join("category"))
entityManager.createQuery(q2).getResultList();
Can you help me please with this problem? I want use this method for find the specific nick in my database (It made with Apache Derby). I have used the EntityManager and mapping Persistence - Entity classes from database in the NetBeans.
public static boolean findByNick(String nick) {
List<eng.db.User> ret;
EntityManager em = getEntityManager();
Query q = em.createQuery("SELECT * FROM User u WHERE u.nick =:nick");
q.setParameter("nick", nick);
ret = q.getResultList();
em.close();
boolean hodnota = false;
if (ret.isEmpty()) {
hodnota = true;
}
return hodnota;
}
I get this error:
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Syntax error parsing [SELECT * FROM User u WHERE u.nick =:nick)].
[21, 21] A select statement must have a FROM clause.
[7, 7] The left expression is missing from the arithmetic expression.
[9, 20] The right expression is not an arithmetic expression.
[41, 42] The query contains a malformed ending.
Where is the problem please?
If nick is the primary key of your entity (#Id), then use:
return em.find(eng.db.User, nick) != null;
Or if not:
Query q = em.createQuery("SELECT TRUE FROM User u WHERE u.nick =:nick");
q.setParameter("nick", nick);
return !q.getResultList().isEmpty();
By returning a simple boolean, you minimize the DB response.
It should be
UPDATE
according to your comment now the query should be:
SELECT u.userID, u.enterKey, u.nick
FROM User u
WHERE u.nick = ?
or with named param
SELECT u.userId, u.enterKey, u.nick
FROM User u
WHERE u.nick = :nick
where usereID, enterKey and nick are fields(properties) of your entity type User.
Your User class should look pretty much like this
#Entity
public class User {
#Id
private long userId;
#column(name="EnterKey"
private String enterKey;
#column(name="nick")
private String nick;
// setter getter
}
Regard that this hql and you use the class and property names of the object model which you defined as arguments for the query.
in your query Hibernate or any other JPA implementation creates a list of objects of type User using the mapping you defined. The expression * can not be associated with an object name of this type. The equivalent to * in sql is in object related query languages just the of the alias of the from clause in your case "u" since the from clause looks like this:
From User u
If you want just to select separate fields of your Entity you have to declare
Select alias.property
from Entity alias
or in your special case
Select u.nick
From User u
In this case instances of type User are created and the field nick is set.
I have a data model that looks like this (simplified example):
public class Address { private List<AddressLine> addressLines; }
public class AddressLine { private String value; private String type; }
I am trying to use the Criteria API to search for Addresses in the database that contain specific combinations of AddressLines. For example, to retrieve all addresses that contain the address lines {(type="CITY", value="London"), (type="COUNTRY", value="GB")}. I haven't been able to find any examples of such a query.
As far as I have been able to get is to query for an Address based on a single AddressLine.
session.createCriteria(Address.class)
.createCriteria("addressLines")
.add(Restrictions.and(Restrictions.eq("type", type), Restrictions.eq("value", value))).list()
If I add a restriction for a second address lines the SQL that hibernate generates is basically asking SELECT x WHERE x.y = 'a' AND x.y = 'b' so will never return any results.
I have found similar questions being asked before but none of them have an accepted or voted for answer.
You need to write the Criteria equivalent of
select a from Address a where
exists (select line1.id from AddressLine line1 where line1.address.id = a.id
and line1.type = 'CITY'
and line1.value = 'London')
and exists (select line2.id from AddressLine line where line2.address.id = a.id
and line2.type = 'COUNTRY'
and line2.value = 'GB')
This means writing a DetachedCriteria for each subquery, with an id projection, and using these detached criterias as argument of two Subqueries.exists() calls. The alias of the address entity in the main criteria can be used in the detached criterias to implement the line1.address.id = a.id restriction.