I am trying to migrate my Spring project from Hibernate to ObjectDB. On ObjectDB page, they say that ObjectDB is 100% compatible with JPA. However, I have problem with this JPQL query:
SELECT e FROM Employee e WHERE e.present = false AND NOT EXISTS
(SELECT c FROM Computer c WHERE c.employeeEntity = e)
ORDER BY e.name
with Hibernate, there was no problem with this query, but ObjectDB throws exception:
com.objectdb.o.UserException: Unexpected query token 'EXISTS'
Second problem is with Criteria Language. This code:
In<Employee> inExpression = cb.in(root.get(Computer_.employeeEntity));
for (Long id : emplIds) {
Employee e = new Employee(id);
inExpression = inExpression.value(e);
}
list.add(inExpression);
was working with Hibernate, with ObjectDB it is throwing:
com.objectdb.o.UserException: Unexpected query token ':l2'
at com.objectdb.o.MSG.d(MSG.java:61)
at com.objectdb.o.TKN.J(TKN.java:765)
at com.objectdb.o.QNF.B(QNF.java:894)
at com.objectdb.o.QNF.I(QNF.java:1294)
at com.objectdb.o.QNF.k(QNF.java:315)
at com.objectdb.o.QNF.H(QNF.java:1270)
at com.objectdb.o.QNF.k(QNF.java:210)
at com.objectdb.o.QNF.t(QNF.java:611)
at com.objectdb.o.QNF.t(QNF.java:605)
at com.objectdb.o.QNF.k(QNF.java:218)
at com.objectdb.o.QNF.j(QNF.java:135)
at com.objectdb.o.QRC.z(QRC.java:321)
at com.objectdb.o.QRC.v(QRC.java:212)
at com.objectdb.o.QRC.u(QRC.java:166)
at com.objectdb.o.QRM.U6(QRM.java:250)
at com.objectdb.o.MST.U6(MST.java:933)
at com.objectdb.o.WRA.U6(WRA.java:291)
at com.objectdb.o.WSM.U6(WSM.java:113)
at com.objectdb.o.STC.r(STC.java:449)
at com.objectdb.o.SHN.aj(SHN.java:489)
at com.objectdb.o.SHN.K(SHN.java:156)
at com.objectdb.o.HND.run(HND.java:132)
at java.lang.Thread.run(Unknown Source)
Does anybody have any idea how to solve these problems?
Milan
com.objectdb.o.UserException: Unexpected query token 'EXISTS'
ObjectDB doesn't know EXISTS. See http://www.objectdb.com/java/jpa/query/jpql/comparison.
Instead you can use IS NOT NULL to validate the existence. Be aware that SELECT c FROM Computer c WHERE c.employeeEntity = e must return a single instance and not a multi row resultset.
This is not an ObjectDB issue, cause it is rooted in SQL / sql dialect.
See https://stackoverflow.com/a/6808503/1549387
com.objectdb.o.UserException: Unexpected query token ':l2'
Can you print the stack trace of this? It looks like a unknown named parameter. Could you send the logging level to FINE or FINEST to view the generated SQL?
Related
I'm currently building a native SQL query with Spring Data JPA that uses a #SqlResultSetMapping. The query looks filters the rows based on certain parameters and then returns all of the columns of an entity table plus additionally it calculates another column on the fly. Something like this:
#Entity
#NamedNativeQuery(
name = "Entity.searchBySearchParams",
resultSetMapping = "SearchResultMapping",
query = "select entity.*, (*calculation*) as anotherField from ..."
)
#SqlResultSetMapping(
name = "SearchResultMapping",
entities = #EntityResult(entityClass = Entity.class),
columns = #ColumnResult(name = "anotherField", type = double.class)
)
public class Entity { ... }
And then I'm trying to call this native, named query from my repository (which extends JpaRepository<T, Long>) like that:
#Query(nativeQuery = true, name = "Entity.searchBySearchParams")
List<Object[]> searchBySearchParams( ... lots of params ... );
Where I'm expecting searchBySearchParams(...)[0] to be of type Entity and searchBySearchParams(...)[1] of type Double.
Unfortunately I'm getting this exception when trying to call the above repository method:
org.springframework.dao.InvalidDataAccessApiUsageException: Cannot create TypedQuery for query with more than one return; nested exception is java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
....
Which is weird since calling the query and applying my result set mapping directly by invoking the EntityManage#createNamedQuery method worked perfectly fine.
Am I missing something or should I post this to the Spring Data Jira? Neither JPA's nor Spring's documentation provided information for my case ...
More Background Info:
Actually the additional column anotherField is a transitive property on my Entity. I haven't found a way of mapping that column to the transitive property, which is why my repository method currently returns Object[].
I am developing a NamedQueryManager EJB that receives a JPQL string from a client and returns a query that only selects data that the user is authorized to read. For example, if the client program wants Companies, it would create the following query and send to the NamedQueryManager.
SELECT c FROM Company c
The NamedQueryManager would consider the query and the current user and if the user doesn't have full permissions to read Company entities would return a query similar to the following:
SELECT c FROM Company c where c.reader = :user
Instead of creating my own parser, I investigated EclipseLink 2.6.1 and found that I could perform the following to parse the query:
JPQLExpression jpql = new JPQLExpression(jpqlString, new JPQLGrammar2_1());
if (jpql.getQueryStatement() instanceof SelectStatement) {
logger.debug("JPQL Expression is a Select statement.");
} else if (jpql.getQueryStatement() instanceof UpdateStatement) {
logger.debug("JPQL Expression is a Update statement.");
} else if (jpql.getQueryStatement() instanceof DeleteStatement) {
logger.debug("JPQL Expression is a Delete statement.");
} else {
logger.debug("JPQL Expression is an unknown statement.");
}
I could then loop through the children of the QueryStatement and determine the pieces of the statement. For example, the following loops through the Select clause.
SelectStatement st = (SelectStatement) jpql.getQueryStatement();
logger.debug("JPQL Select Statement: {}", st);
logger.debug("********************");
SelectClause sc = (SelectClause) st.getSelectClause();
logger.debug("Select Clause: {}", sc);
for (Expression e : sc.children()) {
logger.debug("Child: {}", e);
}
for (Expression e : sc.orderedChildren()) {
logger.debug("Ordered Child: {}", e);
}
So my question is am I on the correct path for using EclipseLink to parse and modify my JPQL?
I am comfortable with the parsing but how do I modify? Should I build a new JPQL string using the parsed JPQL or can I add information to the parsed JPQL directly to create the new query?
I began investigating how I could determine if the passed jpql string is valid and found references to the HermesParser class in the org.eclipse.persistence.internal.jpa.jpql package.
Should I stay away from "internal" packages?
I don't think that the following code which I am using to parse the jpql string uses the HermesParser but the org.eclipse.persistence.jpa.jpql.parser package-info states that "This is the core of Hermes,..."
JPQLExpression jpql = new JPQLExpression(jpqlString, new JPQLGrammar2_1());
So this leads me to ask what is Hermes?
Any big picture help or references would be greatly appreciated.
Note: This is a continuation of the following question.
Should I use #NamedQuery annotation or addNamedQuery method?
I am trying downloading all records from table in h2 buildin database in playframework.
I am facing an error:
[IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: * near line 1, column 8 [SELECT * FROM TABLE]]
Method CODE i class Table:
#Transactional(readOnly=true)
public static Result view() {
Query query = JPA.em().createQuery("SELECT * FROM TABLE");
List<Table> downloaded_from_db = query.getResultList();
System.out.println(downloaded_from_db.getClass());
return ok(view.render("none"));
}
Please help me. I would like to see downloaded records in console in simple view.
Please give me some tips or good tutorial.
After changing my class loooks like this:
#Transactional(readOnly=true)
public static Result view() {
List<MedicalIncidents> data = JPA.em()
.createNativeQuery("SELECT * FROM MedicalIncident")
//.createQuery("Select m from MedicalIncident m")
.getResultList();
System.out.println(data);
AND I think it works, cause I have 2 entries in that table in database:
But System.out.println(data) return in plaay console:
[[Ljava.lang.Object;#70a0c9be, [Ljava.lang.Object;#4c1d12b6]
But it should return this object by model name like in example: computer-database-jpa:
[models.Computer#214c6fde, models.Computer#63728eb3, models.Computer#75f6bcc6, models.Computer#19e3a7ab, models.Computer#3114d8d4, models.Computer#4fa75f78, models.Computer#756ce822, models.Computer#40fc4c68, models.Computer#73fc612c, models.Computer#3e4fcb31]
So I think that there is something wrong with it. Please help
You mxied SQL queries with JPQL query. The method you used createQuery needs an JPQL query:
SELECT e FROM Entity e
Also please note in JPQL there is no SELECT *. If you want to write a SQL query, use the method em.createNtiveQuery().
I'am new in JAVA and JPA.
I use command
select * from asm.attendant where staff_no='0004' and node_code='KT1' and date(attendant_date) = '2013-05-13';
in MySQL it's work
but
when i use in JPA
public List<Attendant> listAttendantByStaffNoAndNodeCodeAndDateWs(String staffNo,String nodeCode,String attendantDateData) throws ParseException {
Date attendantDate = new SimpleDateFormat("yyyy-MM-dd").parse(attendantDateData);
Query result = em.createQuery("SELECT a FROM Attendant a WHERE a.staffNo = :staffNo AND a.nodeCode = :nodeCode AND DATE(a.attendantDate) = :attendantDate", Attendant.class);
result.setParameter("staffNo", staffNo);
result.setParameter("nodeCode", nodeCode);
result.setParameter("attendantDate", attendantDate);
return result.getResultList();
}
it's not work.
error
Caused by: Exception [EclipseLink-8025] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Syntax error parsing the query [SELECT a FROM Attendant a WHERE a.staffNo = :staffNo AND a.nodeCode = :nodeCode AND DATE(a.attendantDate) = :attendantDate], line 1, column 88: unexpected token [(].
Internal Exception: NoViableAltException(83#[()* loopback of 383:9: (d= DOT right= attribute )*])
DATE() is not valid JPQL. In JPA createQuery() takes JPQL not SQL. If you want SQL use createNativeQuery().
Or, in JPQL just mark the date as a parameter :date any set the parameter to your instance of java.sql.Date.
I always get the same error when using the criteria API:
Local Exception Stack:
Exception [EclipseLink-6075] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.QueryException
Exception Description: Object comparisons can only use the equal() or notEqual() operators. Other comparisons must be done through query keys or direct attribute level comparisons.
Expression: [
Relation operator LIKE
Query Key rootId
Base de.uni.entities.Diary
Constant Testaccount]
Query: ReportQuery(referenceClass=Diary )
The code with the criteria API is the following:
....
CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
// Restrictions
Predicate[] predicate = new Predicate[1];
// From-clause
Root<User> root2R = cq.from(User.class);
predicate[0] = cb.like(root2R.<String> get("rootId"), id);
Join<Clazz, Diary> friends2R;
friends2R = root2R.join("diaries");
cq.where(predicate);
// Select-clause
cq.select((Selection<? extends Clazz>) friends2R);
Query query = getEm().createQuery(cq);
List<Object> data = query.getResultList();
return data;
}
The problem exists because of the following two lines:
" Join friends2R;
friends2R = root2R.join("diaries");"
Without the mapping (with an adjusted select-clause) i would get the searched User with the fitting rootId, so that there occurs no error. But now i wanna map the User with the Diaries and show all diaries of the User-entity. But it always ends in the error ahead. Whether i use "like" or "equal", it doesn't work.
The generell code shouldn't have an error, because i'm using the same code already to get all mapped Users of a User (many to many relation) => no problem.
I just don't understand, why this error occurs and especially why it mentions the Diary as Base although the user should be mentioned as the base-class...and the id is right too and also appears so in the database...
I really hope that you can help me, thanks in advance!
How is rootId mapped, using a Basic, or OneToOne?
Seems to be a bug, please log the bug on EclipseLink.
Your code does not seem correct though, the
CriteriaQuery cq = cb.createQuery(User.class);
should be,
CriteriaQuery cq = cb.createQuery(Diary.class);
should it not?
Doesn't Diary also have a relationship to User? You could just query Diary where its user has the id.