Hibernate: org.hibernate.hql.ast.QuerySyntaxException: unexpected token - java

I am using Hibernate and I have this query:
List<Person> list = sess.createQuery("from Person").list();
With this statement, I get all persons from the database.
But now, I only want some persons.
My database scheme:
Project <- Project_Person -> Person
So I only want Persons which are a member of a project.
With the SQL statement on the database I get the desired result:
select * from Person inner join Project_Person
on person_id = id
where project_id = 1;
So I thought, I can write this with Hibernate:
List<Person> list =
sess.createQuery(
"from Person inner join Project_Person
on person_id = id
where project_id = "+projectId).list();
But here I get an error:
SERVE: Servlet.service() for servlet myproject3 threw exception
org.hibernate.hql.ast.QuerySyntaxException: unexpected token: on near line 1, column 65 [from com.mydomain.myproject.domain.Person inner join Project_Person on person_id = id where project_id = 1]
at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:54)
at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:47)
at org.hibernate.hql.ast.ErrorCounter.throwQueryException(ErrorCounter.java:82)
at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:284)
at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:182)
at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:124)
at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156)
at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:135)
at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1770)
at sun.reflect.GeneratedMethodAccessor33.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
at $Proxy26.createQuery(Unknown Source)
...
Does anyone has an idea what's wrong here?
Best Regards.
New Error:
SERVE: Servlet.service() for servlet myproject3 threw exception
org.hibernate.QueryException: could not resolve property: project of: com.mydomain.myproject.domain.Person [from com.mydomain.myproject.domain.Person p where p.project.id = :id]
n:m relation:
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "Project_Person",
joinColumns = {#JoinColumn(name="project_id", referencedColumnName="id")},
inverseJoinColumns = {#JoinColumn(name="person_id", referencedColumnName="id")}
)
private Set<Person> persons = new HashSet<Person>();
#ManyToMany(mappedBy="persons")
private Set<Project> projects = new HashSet<Project>();
Full Error
Hibernate: select project0_.id as id1_, project0_.createDate as create2_1_, project0_.description as descript3_1_, project0_.name as name1_ from Project project0_ where project0_.id=1
Hibernate: select person0_.id as id0_0_, project2_.id as id1_1_, person0_.email as email0_0_, person0_.firstName as firstName0_0_, person0_.lastName as lastName0_0_, project2_.createDate as create2_1_1_, project2_.description as descript3_1_1_, project2_.name as name1_1_ from Person person0_ inner join Project_Person projects1_ on person0_.id=projects1_.person_id inner join Project project2_ on projects1_.project_id=project2_.id where project2_.id=?
15.12.2010 16:42:26 org.apache.catalina.core.ApplicationDispatcher invoke
SERVE: Servlet.service() for servlet myproject3 threw exception
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.mydomain.myproject.domain.Person

HQL queries are written against the object model, not against the database schema.
Therefore your query depends on how you mapped the relationship between persons and projects. For example, in Person has a many-to-one relationship to Project via project property, the query will look like this:
List<Person> list = sess.createQuery(
"from Person p where p.project.id = :id")
.setParameter("id", projectId)
.list();
EDIT: In the case of many-to-many relationship you need
select p from Person p join p.projects proj where proj.id = :id
Also not that passing parameters via string concatenation is a bad practice, use setParameter() instead.

Related

How to Use Multiple Join on Hibernate?

I have these following Classes:
class Person(){
#OneToMany(mappedBy="person")
private List<PersonRoles> roles;
}
class PersonRoles(){
#ManyToOne
#JoinColumn(name = "person_id", nullable = false)
private Person person;
#ManyToOne
#JoinColumn(name = "request_id")
private Request request;
}
class Request(){
#OneToMany(mappedBy="request")
private List<PersonRoles> roles;
}
Now I am going to fetch all person based on a given request id and his roles by using hibernate and inner join but my log is telling me that my table doesn't exist. This is my query so far:
sql = "SELECT p.* FROM person AS p INNER JOIN p.roles ON p.roles.personId = p.id
INNER JOIN request AS r ON p.roles.requestId = r.id AND p.roles.role like :item
AND r.id = :id";
query = session.createSQLQuery(sql);
query.addEntity(Person.class);
query.setParameter("item", "Members");
query.setParameter("id", id);
person = (Person) query.uniqueResult();
and this is what i received on the log:
Table 'p.roles' doesn't exist
Did i forget some hibernate annotation? or My query has something wrong?
Brief reason
your syntax of SQL is wrong
Detailed explanation
here is the syntax of inner join example
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name;
for multiple inner join
SELECT *
FROM table1
INNER JOIN table2
ON table1.primaryKey=table2.table1Id
INNER JOIN table3
ON table1.primaryKey=table3.table1Id
but you have used INNER JOIN p.roles there should be a table name after the INNER JOIN, not a column name.
that's why you got an error, moreover, use HQL instead of SQL in hibernate it is a good practice.
happy coding!

joining more than two tables in hibernate

i want to join 4 tables with hibernate. i write following code for fetch name , teacher detail and schedules of course:
public Student getStudentDetail(int studentId) {
Criteria criteria = createEntityCriteria();
criteria.add(Restrictions.eq("id", studentId));
criteria.setFetchMode("attends", FetchMode.JOIN);
Criteria attendCriteria = criteria.createCriteria("attends", "attend")
.setFetchMode("course", FetchMode.JOIN);
Criteria courseCriteria = attendCriteria.createCriteria("course", "course")
.setFetchMode("scheduleList", FetchMode.JOIN);
Criteria scheduleCriteria = courseCriteria.createCriteria("scheduleList", "schedule");
return (Student) scheduleCriteria.uniqueResult();
}
the query created by hibernate is to get detail is:
select
this_.id as id1_4_4_,
this_.code_melli as code_mel2_4_4_,
this_.email as email3_4_4_,
this_.mobile as mobile4_4_4_,
this_.name as name5_4_4_,
this_.phone as phone6_4_4_,
this_.register_date as register7_4_4_,
attend1_.course_id as course_i1_1_0_,
attend1_.student_id as student_2_1_0_,
attend1_.score as score3_1_0_,
course2_.id as id1_2_1_,
course2_.cluster as cluster2_2_1_,
course2_.code as code3_2_1_,
course2_.end_date as end_date4_2_1_,
course2_.name as name5_2_1_,
course2_.salary as salary6_2_1_,
course2_.start_date as start_da7_2_1_,
course2_.students as students8_2_1_,
course2_.teacher_id as teacher10_2_1_,
course2_.tuition as tuition9_2_1_,
schedule3_.course_id as course_i1_2_6_,
schedule3_.course_id as course_i1_3_6_,
schedule3_.day as day2_3_6_,
schedule3_.course_id as course_i1_3_2_,
schedule3_.day as day2_3_2_,
schedule3_.endt as endt3_3_2_,
schedule3_.start as start4_3_2_,
teacher8_.id as id1_5_3_,
teacher8_.code_melli as code_mel2_5_3_,
teacher8_.email as email3_5_3_,
teacher8_.mobile as mobile4_5_3_,
teacher8_.name as name5_5_3_,
teacher8_.phone as phone6_5_3_,
teacher8_.register_date as register7_5_3_
from
public.students this_
inner join
public.attend attend1_
on this_.id=attend1_.student_id
inner join
public.courses course2_
on attend1_.course_id=course2_.id
left outer join
public.schedule schedule3_
on course2_.id=schedule3_.course_id
left outer join
public.teachers teacher8_
on course2_.teacher_id=teacher8_.id
where
this_.id=?
but it has problem:
setFetchMode method dont work. beacuse program throw following exception:
threw 'org.hibernate.LazyInitializationException' exception.

JPQL include elementCollection map in select statement

I have an #Entity class Company with several attributes, referencing a companies Table in my db. One of them represents a Map companyProperties where the companies table is extended by a company_properties table, and the properties are saved in key-value format.
#Entity
#Table(name = "companies")
public class Company extends AbstractEntity {
private static final String TABLE_NAME = "companies";
#Id
#GeneratedValue(generator = TABLE_NAME + SEQUENCE_SUFFIX)
#SequenceGenerator(name = TABLE_NAME + SEQUENCE_SUFFIX, sequenceName = TABLE_NAME + SEQUENCE_SUFFIX, allocationSize = SEQUENCE_ALLOCATION_SIZE)
private Long id;
//some attributes
#ElementCollection
#CollectionTable(name = "company_properties", joinColumns = #JoinColumn(name = "companyid"))
#MapKeyColumn(name = "propname")
#Column(name = "propvalue")
private Map<String, String> companyProperties;
//getters and setters
}
The entity manager is able to perform properly find clauses
Company company = entityManager.find(Company.class, companyId);
However, I am not able to perform JPQL Queries in this entity and retrieve the Map accordingly. Since the object is big, I just need to select some of the attributes in my entity class. I also do not want to filter by companyProperties but to retrieve all of them coming with the proper assigned companyid Foreign Key. What I have tried to do is the following:
TypedQuery<Company> query = entityManager.createQuery("SELECT c.id, c.name, c.companyProperties " +
"FROM Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
The error I get is:
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Problem compiling [SELECT c.id, c.name, c.companyProperties FROM Company as c where c.id = :id]. [21, 40] The state field path 'c.companyProperties' cannot be resolved to a collection type.
org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1616)
org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1636)
com.sun.enterprise.container.common.impl.EntityManagerWrapper.createQuery(EntityManagerWrapper.java:476)
Trying to do it with joins (the furthest point I got was with
Query query = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id");
does not give me either the correct results (it only returns the value of the property and not a list of them with key-value).
How can I define the right query to do this?
Your JPA syntax looks off to me. In your first query you were selecting individual fields in the Company entity. But this isn't how JPA works; when you query you get back the entire object, with which you can access any field you want. I propose the following code instead:
TypedQuery<Company> query = entityManager.createQuery("from Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
Similarly, for the second join query I suggest the following code:
Query query = entityManager.createQuery("SELECT c" +
"FROM Company c LEFT JOIN c.companyProperties p WHERE c.id = :id");
query.setParameter("id", companyId);
List<Company> companies = query.getResultList();
The reason why only select a Company and not a property entity is that properties would appear as a collection inside the Company class. Assuming a one to many exists between companies and properties, you could access the propeties from each Company entity.
You are expecting to get a complete Company object when doing select only on particular fields, which is not possible. If you really want to save some memory (which in most cases would not be that much of a success) and select only some field, then you should expect a List<Object[]>:
List<Object[]> results = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id")
.setParameter("id", companyId)
.getResultList();
Here the results will contain a single array of the selected fields. You can use getSingleResult, but be aware that it will throw an exception if no results were found.

hibernate self referencing table get rows by fk

table Student
----------------
id | somecolumn with string| fk(which is self referencing ID of the same table)
how can i make hibernate query that will fetch all items where value of id will match value of fk.
here is what i have tried but it doesn't works (it returns only 1 result instead of result set)
List<Student> list = (List<Student>) sessionFactory
.getCurrentSession()
.createQuery("from Student p join p.studentFKs p2 where p2.id = :parentId")
.setParameter("parentId", parentId).list();
can someone help me solve the mistery? i know that it can be achieved with Hibernate criterias also.
UPDATE answer is to change query to(join was invalid.. ):
select p from Student p join p.student p2 where p2.id = :parentId
i use something like this and this is work
property of join inside entity Student :
#ManyToMany(cascade = CascadeType.REFRESH)
private Set<Student> testJoins = new HashSet<Student>();
HQL to get that set :
select a.testJoins from Student a where a.id = :parentId
maybe you can change your query from p2.id = :parentId to-->> p.id = :parentId

hibernate "where" query only works for id field

I have a problem with a Hibernate query that looks as follows:
List persons = getList("FROM creator.models.Person p WHERE p.lastName="+userName);
(the getList(String queryString) method just executes the query using a session factory.)
This is my person class:
#Entity
#Table(name="persons")
public class Person{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name="first_name", nullable=false, updatable=true)
private String firstName;
#Column(name="last_name", nullable=false, updatable=true)
private String lastName;
/// etc
And this is the table:
CREATE TABLE persons(
id INTEGER NOT NULL AUTO_INCREMENT,
first_name CHAR(50),
last_name CHAR(50),
abbreviation CHAR(4),
PRIMARY KEY (id)
);
Searching for a person with the name TestName, I get an exception with this message:
org.hibernate.exception.SQLGrammarException: Unknown column 'TestName' in 'where clause'
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:82)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
//etc
The query created by Hibernate looks like this:
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select person0_.id as id8_, person0_.abbreviation as abbrevia2_8_, person0_.first_name as first3_8_, person0_.last_name as last4_8_ from persons person0_ where person0_.last_name=TestName
Dec 10, 2012 5:14:26 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
Searching for the id (...WHERE p.id="3") works fine, by the way!
I hope somebody knows what is going wrong because for me the query looks right and I can't find out why the lastName is seen as a column name suddenly.
You need to put userName in quotes:
"FROM creator.models.Person p WHERE p.lastName='"+userName+"'";
Or (which is much better) to use parameters
replace your hql with:
Query query = session.createQuery("from creator.models.Person p where p.lastName = ?")
.setParameter(0, userName);
List persons = query.list();
that way you also prevent sql-injection.
you need to wrap your parameter with single quotes:
List persons = getList("FROM creator.models.Person p WHERE p.lastName='"+userName+"'");
but much better with a parameterized query:
String hql = "FROM creator.models.Person p WHERE p.lastName= :userName";
Query query = session.createQuery(hql);
query.setString("userName",userName);
List results = query.list();

Categories

Resources