EclipseLink "SQL string is not Query" - jpa

I'm running EclipseLink on WLS 10.3.5.
I'm trying to use #NamedNativeQuery annotation, but all the SQL I try causes an "Internal Exception: java.sql.SQLException: SQL string is not Query" exception.
Even a simple SELECT * FROM TABLE causes that error where TABLE is the table that the containing Entity is mapped to.
The annotation is:
#NamedNativeQuery(name = AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT, query = "SELECT * FROM ANNOUNCEMENT_DELIVERY_LOG", resultClass = AnnouncementDeliveryLog.class)
The query is being executed with:
em.createNativeQuery(AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT).getResultList();
I can't find a good way to get more useful information from the system so any information is appreciated.

Wrong method is in use. Method createNativeQuery takes native SQL string as an argument. In given code argument seems to be name of the native query. Method createNamedQuery should be used, it takes name of the native query as an argument.

Related

Queries creation from method name in Spring JPA

I want to fetch record based on event type and last updated user so i am writing a method to fetch data in SpringData JPA.
Below is the code for reference:
List<StrataLog> getEventTypeAndUserLastUpdatedOrderByLoggerLevelAscAndUoidAsc(String eventType,
String userLastUpdated);
I am getting below error:
Caused by:
org.springframework.data.mapping.PropertyReferenceException: No
property asc found for type String!
List getEventTypeAndUserLastUpdatedOrderByLoggerLevelAscAndUoidAsc(String
eventType, String userLastUpdated);
Expected Output should be it should return rows from the database.
If you want to Order by multiple properties you should not add And between the properties
This should work:
List<StrataLog> findAllByEventTypeAndUserLastUpdatedOrderByLoggerLevelAscUoidAsc(String eventType,String userLastUpdated);
But as you can see the method-name is getting quit complex, you should consider using a #Query or use Sort as extra parameter

Named query with input parameter

I am learning JPA with Hibernate, using maven as well. My problem is How can I use input parameters with UPDATE and SET clause in named query ?
#NamedQuery(name = "updateEmailAddress", query = "Update User u set u.email = :email where u.username = :username")
It gives me an error that a parameter can only be used in the WHERE or HAVING clause. I referred several article but still cannot find the proper solution.
In JPA 2.0 and below, parameters are not allowed in the set clause of a named query; only literals. This limitation is lifted if you are using JPA 2.1.
From what I can gather, you are not using JPA 2.1. Hence, I'll give you a couple of ways to sidestep this limitation.
Option 1:
Use the createQuery method and pass a dynamically generated string to the method.
String queryString = generateQueryString(email, username);
entityManager.createQuery(queryString).executeUpdate();
Option 2:
Update the associated entity and merge.
List<User> result = entityManager.createQuery('select u from user u where
u.username = :username').setParameter('username', username).getResultList();
for (User user : result) {
user.setEmail(email);
entityManager.merge(user);
}
Option 3:
Create the query using HQL not JPQL. I haven't tested this nor do I recommend it because you are going behind the entity manager's back.
Query q = sessionFactory.getCurrentSession().createNamedQuery('updateEmailAddress');
q.setParameter('email', email);
q.setParameter('username', username);
q.executeUpdate();
While in fact until JPA 2.1 this was not allowed, you can actually use it because the providers will let you provide parameters in that way (which turns out to be a good thing!).
It seems the JPA providers are not conforming to the spec regarding this validation, and I think is just because it didn't make any sense (you can see in 2.1 it is now permitted). "Why would me make it difficult do developers?"
I am also using EclipseLink 2.3.1 and it is working fine.
The recommended solution
Just disable Eclipse's JPQL query validation.
If the provider accepts it, you should be fine, otherwise you need to conform to the spec. Very simple. Code will be cleaner and it will conform to recent evaluations of the spec.
Just go to: Preferences > Java Persistence > JPA > Errors/Warnings > Queries and Generators > Invalid or incomplete JPQL queries: and Ignore it
Check this article for details:
Conclusion
Hibernate does not follow the specification on this point but one
might guess that the new version of the JPA-spec will allow this
behavior as indicated by the draft JSR. JBoss Tools is probably
validating the query against the JPQL-grammar which is based on the
specification and is therefore showing a validation error.
And this is the resolution:
End remark
After a discussion in out team we decided to keep the current
implementation despite the breach of specification. Changing the
behavior would mean string concatenation or string substitution to
build the query and the current approach is much cleaner. As we see no
indications of a shift in persistence provider or application server
at this stage we believe the gains of keeping the code are larger than
the risks at this point.
Can you try positional parameter and see if it works?
#NamedQuery(name = "updateEmailAddress", query = "UPDATE User u SET u.email = ?1 WHERE u.username = ?2")
//The parameter needs to be passed as
query.setParameter(1, "the_emailaddress");
query.setParameter(2, "the_username");
You must build a query named as follows:
Query query = getEntityManager().createNamedQuery("updateEmailAddress");
query.setParameter("email", "email#test.com");
query.setParameter("username", "emailuser");
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
Sources:
Hibernate 3.6 - DML-style operations
hibernate 4.2 - HQL for UPDATE and DELETE
Hibernate Query examples (HQL)
Hibernate Query Languages

Writing custom n1ql queries in spring

I'm trying to query a spring-data couchbase repository using N1QL queries. I have two doubts:
I'm using #Query annotation to generate queries, my code looks like this:
#Query("#{#n1ql.selectEntity} WHERE $0 = $1 AND #{#n1ql.filter}")
public Page<GsJsonStore> matchJson(String term, String value, Pageable pageable);
//Query
Page<GsJsonStore> p = repo.matchJson("_object.details.status", "ready", pg);
This query doesn't return any results. However, when I run the same query (below) in cbq I get the desired result:
select * from default where _object.details.status = 'ready';
How can I view the query string generated by the Couchbase repository? I'm using spring-boot. Am I correct in using the #Query annotation for this use-case?
Also, how can I perform n1QL queries on CouchbaseOperations template? I know that there's a findByN1QL method, but I didn't find any good documentation about it. Could someone please explain how to use this?
The query looks ok. You did persist your GsJsonStore entities using the Spring Data Couchbase repository did you?
In order to log all the queries generated and executed by the framework (including inline queries like in your case), you can configure the logger like so in a logback.xml configuration:
<logger name="org.springframework.data.couchbase.repository.query" level="debug"/>
You'll see that the query that got executed and the query that you ran in cbq are not the same, since at least you didn't use a WHERE clause.
In CouchbaseOperations there are two methods relative to N1QL queries:
findByN1QL: this expects specific structure of the query, in order to make sure all data necessary to correct deserialization of a Spring Data annotated entity is selected (which is the purpose of the #n1ql.selectEntity and #n1ql.filter SpEL).
findByN1QLProjection is more free-form. If Jackson can deserialize the results of the provided query to the requested Class, then it will. As such, the SELECT clause is much less implicitly restricted in this method.
To use both, you must pass in a N1qlQuery object from the SDK. Such queries can be constructed using factory methods of the N1qlQuery class, for example:
//a version of the query that is constructed from positional parameters
N1qlQuery queryWithParameter = N1qlQuery.parameterized("SELECT name FROM `beer-sample` WHERE name LIKE $0", JsonArray.from("%dog%"));
//let Spring Data execute the query, projecting to the String class
List<String> beerNamesContainingDog = template.findByN1QLProjection(queryWithParameter, String.class);

Open JPA : An error occurred while parsing the query filter 'MY_QUERY' Error message: No field named "accessAuthorizationVs" in class "MyEntityClass"

I have configured it in my Rational Software Architect 8.0.4, by enabling the JPA 1.0 facet. It autogenerates almost all my entity classes except for the id's. So I manually add them. I am trying to query a simple table APP_USER that has one-to-many relation to ACCESS_AUTHORIZATION table. See below for the configurations and entity classes.
When I try to execute a simple named query which is
SELECT a.accessAuthorizationVs, a.empName, a.userCnum FROM AppUserEntity a WHERE a.userCnum = :userCnum
It throws an exception
**org.apache.openjpa.persistence.ArgumentException: An error occurred while parsing the query filter "SELECT a.accessAuthorizationVs, a.empName, a.userCnum FROM AppUserEntity a WHERE a.userCnum = :userCnum". Error message: No field named "accessAuthorizationVs" in class "class com.xxx.xxx.xxx.services.integration.entity.AppUserEntity".**
at org.apache.openjpa.kernel.exps.AbstractExpressionBuilder.parseException(AbstractExpressionBuilder.java:118)
at org.apache.openjpa.kernel.exps.AbstractExpressionBuilder.traversePath(AbstractExpressionBuilder.java:284)
at org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getPath(JPQLExpressionBuilder.java:1382)
at org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getPathOrConstant(JPQLExpressionBuilder.java:1337)
Here's a snapshot of my persistence.xml:
Can anyone guide me what I am doing wrong here? The field by that name is clearly defined in my entity class. Also I would like to mention that I had to enhance the classes[followed this] as there was an earlier error about classes not being enhanced.
When you create a named query in OpenJPA, remember that you are writing JPQL, not native SQL. The syntax is similar, but a little different.
In this case, I suggest changing your named query to the following:
SELECT a FROM AppUserEntity a WHERE a.userCnum = :userCnum
This will return an object of the AppUserEntity class which will include the set of AccessAuthorizationV objects (lazy loaded by default).
For more details, see the JPQL Language Reference.

Doubt regarding JPA namedquery

I am trying to execute a namedquery
#NamedQuery(name="getEmployeeDetails",query="select e.username,e.email,e.image,e.firstname,e.lastname from Employee e where e.empid=?1")
Now when I execute this query in a EJB 3.0 Session Bean what is the object I should return.I tried returning Listits returning a Vector which creates a classcast exception.The employee table contains fields like password and other confidential details which I don't want to fetch.So I am not using select e from Employee e.
I am learning JPA can anyone help.
Below is the sample query which fetches only the required fields, but have to make such constructor for it.
Query : SELECT NEW package_name.Employee(e.username,e.email,e.image,e.firstname,e.lastname) FROM Employee e where e.empid=?1;
It will return Employee entity with selected fields & remaining will have default values.
Inspect the returned type by calling .getClass() on a returned object. I'd guess it's an array.
But this is not really a good way to use JPA. Select the whole entity and then just don't use what you don't need. It's not such a performance hit.