How should I pass values into JPQL query? - java

I'm working on test, that will check if object had been saved into database. Test will save object with unique values and after that I want to fetch this object from database and check if it is not null. Id is auto generated, so I need to find this object by name.
My test looks like this:
#Test
public void shouldAddNewEmployee(){
String firstNameTest = "Jon";
String lastNameTest = "Doe";
double salary1test = 10.0;
String salary2test = "10.00";
String localityTest = "LosAngeles";
String zipCodeTest = "00-000";
String streetTest = "LosAngeles str.";
int streetNumberTest = 10;
Employee testEmployee = new Employee(
firstNameTest,
lastNameTest,
salary1test,
salary2test,
localityTest,
zipCodeTest,
streetTest,
streetNumberTest);
EmployeeRepository.addNewEmployeeFromCLI(testEmployee);
String customQueryFindJonDoe = "select e from Employee e where e.firstName = Jon and e.lastName = Doe";
EntityManager entityManager = JPAUtils.openEntityManager();
List<Employee> foundJonDoe = entityManager.createQuery(customQueryFindJonDoe).getResultList();
Assertions.assertNotEquals(null, foundJonDoe);
if (entityManager.isOpen()) {
entityManager.close();
}
}
after running it I get error:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Jon' in 'where clause'
How should this query look like?

You have to set the parameters on the query:
String customQueryFindJonDoe =
"select e from Employee e where e.firstName = :firstname and e.lastName = :lastName";
EntityManager entityManager = JPAUtils.openEntityManager();
TypedQuery<Employee> q = entityManager.createQuery(customQueryFindJonDoe, Employee.class);
q.setParameter("firstname", "Jon");
q.setParameter("lastName", "Doe");
List<Employee> foundJonDoe = q.getResultList();
More about querying you can find here:
https://docs.oracle.com/javaee/7/tutorial/persistence-querylanguage002.htm#BNBRG
https://www.objectdb.com/java/jpa/query
Or you buy a book
https://www.apress.com/de/book/9781484234198

Related

Select table row using HQL with param

I want to use this HQL query in order to select table row value:
String hql = "select e.token, e.name from Terminals e where e.token = ?";
Terminals terminal = entityManager
.createQuery(hql, Terminals.class)
.setParameter(0, terminalToken)
.getSingleResult();
But I get this result:
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [org.api.entity.Terminals]
What is the proper way to implement this?
Your query return two Objects token and name and not a Terminals Object.
Instead you can use :
Object[] obj = entityManager
.createQuery(hql)
.setParameter(0, terminalToken)
.getSingleResult();
if(obj != null){
Terminals terminal = new Terminals((String) obj[0], (String) obj[1]);
}
Or you can create a constructor in Terminals class which hold two fields :
public Terminals(String token, String name){
this.token = token;
this.name = name;
}
then change your code to be :
String hql = "select new com.package.Terminals(e.token, e.name) from Terminals e where e.token = ?";
Terminals terminal = entityManager
.createQuery(hql, Terminals.class)
.setParameter(0, terminalToken)
.getSingleResult();
IMO, you should not directly call createQuery to assign to a custom object. And there is a possiblity of returning a list.
Query query = entityManager.createQuery(hql).setParameter(0, "something");<br>
List<Object[]> terminals = query.getResultList();
and retrieve the objects with an index as the ff as an example:
StudentDto dto = new StudentDto();
for(Object[] a: std) {
dto = new StudentDto();
dto.setId((long) a[0]); //id
dto.setName(a[1].toString()); //first name
dto.setPassportNumber(a[2].toString()); //last name
}

org.hibernate.exception.SQLGrammarException: could not extract ResultSet - return a matching record from the search query

I am trying to return a distinct record from the database based on the search query. This is my attempt
#SuppressWarnings("unchecked")
#Override
public List<Employee> getAllEmployees(String employeeName) {
String query = "SELECT e. FROM Employees e WHERE e.name like '%"+ employeeName +"%'";
List<Object[]> employeeObjects = hibernateUtil.fetchAll(query);
List<Employee> employees = new ArrayList<Employee>();
for(Object[] employeeObject: employeeObjects) {
Employee employee = new Employee();
long id = ((BigInteger) employeeObject[0]).longValue();
int age = (int) employeeObject[1];
String name = (String) employeeObject[2];
float salary = (float) employeeObject[3];
employee.setId(id);
employee.setName(name);
employee.setAge(age);
employee.setSalary(salary);
employees.add(employee);
}
System.out.println(employees);
return employees;
}
On the above attempt, I have this error
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 'FROM Employees e WHERE e.name like '%john%'' at line 1
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
please how do i modify my query to select a unique record
"SELECT e. FROM Employees e WHERE e.name like " => there is an dot(.) after SELECT e. It should be SELECT DISTINCT e.name FROM Employees ....

jpa native query control entity(part 3)

Retrieve company table
GetEntity.java
String table = "company";
String q = "select * from " +table;
Query query = em.createNativeQuery(q, Company.class);
List<Company> list = query.getResultList();
...
Retrieve staff table
GetEntity.java
String table = "staff";
String q = "select * from " +table;
Query query = em.createNativeQuery(q, Staff.class);
List<Staff> list = query.getResultList();
...
My questions is how do I control the ? from the following:
em.createNativeQuery(q, ?);
List<?> list = q.getResultList();
Any ideas or suggestion?
Another option is to pass the Class entityClass as an argument to your find method and then you can try and derive table name from entityClass by using reflection and use the entityClass as the type argument to your createNativeQuery method.
Hope this helps!

JPA mapping entities with hql column names

I am trying to use a feature like RowMapper which provides me with ResultSet, so that I can set the attributes of my pojo by taking resultSet.getString("column_name") in JPA.
But JPA doesn't seems to provide such a feature.
StringBuffer rcmApprovalSqlString = new StringBuffer(QueryConstants.APPROVAL_DETAILS_SQL);
List<ApprovalDTO> finalApprovalList = null;
Query rcmApprovalTrailQuery = getEntityManager().createQuery(rcmApprovalSqlString.toString());
rcmApprovalTrailQuery.setParameter(1,formInstanceId);
List<?> approvalList = rcmApprovalTrailQuery.getResultList();
finalApprovalList = new ArrayList<ApprovalDTO>();
for(Object approvalObj : approvalList){
Object[] obj = (Object[]) approvalObj;
ApprovalDTO approvalDTO = new ApprovalDTO();
approvalDTO.setDeptName(obj[0]!=null? obj[0].toString() : NAPSConstants.BLANK_STRING);
approvalDTO.setUserId(obj[1]!=null? obj[1].toString()+" "+obj[2].toString() : NAPSConstants.BLANK_STRING);
approvalDTO.setComment(obj[6]!=null? obj[6].toString() : NAPSConstants.BLANK_STRING);
finalApprovalList.add(approvalDTO);
}
So instead of doing approvalDTO.setComment(obj[6]) which is the 6th element of array, can I do something like approvalDTO.setComment(rs.getString("comments")); ?
So if in future my column position change in the query, I will not have to change my DAO code to match the column number.
My hql query = select ad.departmentid.departmentname, ad.userid.userfirstname, ad.userid.userlastname, ad.napsroleid.napsrolename,
ad.approvalstatus, ad.approvaltimestamp, ad.approvalcomments
from ApprovaldetailsTbl ad
where ad.forminstanceid.forminstanceid = ?1
order by approvallevelid asc
With JPA 2.1 you have a great possibility to use SqlResultSetMapping. You can find out more for example here:
http://www.thoughts-on-java.org/2015/04/result-set-mapping-constructor.html
http://www.thoughts-on-java.org/2015/04/result-set-mapping-basics.html
http://www.thoughts-on-java.org/2015/04/result-set-mapping-complex.html
The idea is that instead of doing it as you used to do:
List<Object[]> results = this.em.createNativeQuery("SELECT a.id, a.firstName, a.lastName, a.version FROM Author a").getResultList();
results.stream().forEach((record) -> {
Long id = ((BigInteger) record[0]).longValue();
String firstName = (String) record[1];
String lastName = (String) record[2];
Integer version = (Integer) record[3];
});
you can introduce an annotation:
#SqlResultSetMapping(
name = "AuthorMapping",
entities = #EntityResult(
entityClass = Author.class,
fields = {
#FieldResult(name = "id", column = "authorId"),
#FieldResult(name = "firstName", column = "firstName"),
#FieldResult(name = "lastName", column = "lastName"),
#FieldResult(name = "version", column = "version")}))
and afterwards use the mapping (by specifying mapping name) in your query:
List<Author> results = this.em.createNativeQuery("SELECT a.id as authorId, a.firstName, a.lastName, a.version FROM Author a", "AuthorMapping").getResultList();
I am able to fetch the desired result only with Native query and not with NamedNativeQuery -
Query rcmApprovalTrailQuery = getEntityManager().createNativeQuery(rcmApprovalSqlString.toString(),"ApprovalMapping");
rcmApprovalTrailQuery.setParameter(1,formInstanceId);
List<ApprovaldetailsTbl> approvalList = rcmApprovalTrailQuery.getResultList();
My native query -
String RCM_APPROVAL_DETAILS_SQL = "select * "+
" from ApprovalDetails_TBL ad " +
" where ad.ApprovalDetailsId = ? ";
SqlResultSetMapping -
#SqlResultSetMapping(name="ApprovalMapping",
entities=#EntityResult(entityClass=ApprovaldetailsTbl.class
))
Note that you need to map all the column names to the entity field names if you are not using * in select query e.g -
fields = {
#FieldResult(name = "col1", column = "alais1"),
#FieldResult(name = "col2", column = "alais2")})

Returnings two results sets using JPA

I am using a JPA query to get a result set, then within the same class, I would like to conditionally get more data. Here's what it looks like:
public SchoolUser getCandidatesAsJson(#PathParam("applicationId") String applicationId, #PathParam("userPassword") String userPassword ) {
EntityManager em = createEM();
Query query = em.createQuery("SELECT su FROM SchoolUser su WHERE su.applicationId LIKE :applicationId and su.userPassword LIKE :userPassword", SchoolUser.class);
query.setParameter("applicationId", applicationId);
query.setParameter("userPassword", userPassword);
List <SchoolUser> schoolUser = query.getResultList();
if(!schoolUser.isEmpty()) {
SchoolUser loginRecord = schoolUser.get(0);
int teacherId = loginRecord.getTeacherId();
int studentId = loginRecord.getStundentId();
if(teacherId!=0){
TypedQuery<Classroom> query2 = em.createQuery("SELECT c FROM Classroom c where c.teacherId = :teacherId ORDER BY c.period", Classroom.class);
query2.setParameter("teacherId", teacherId);
List <Classroom> teacherClassList = query2.getResultList();
if(!teacherClassList.isEmpty()){
//put 2nd results set in SchoolUser object - line is commented because it causes an erro
//loginRecord.setClassRooms(teacherClassList);
}
} else if(studentId!=0){
TypedQuery<ClassroomStudent> query3 = em.createQuery("SELECT cs FROM ClassroomStudent cs where cs.statusId = 1 AND cs.studentId = :studentId", ClassroomStudent.class);
query3.setParameter("studentId", studentId);
//put results in SchoolUser object
}
return loginRecord;
} else {
SchoolUser emptyRecord = new SchoolUser();
return emptyRecord;
}
}
The error comes from putting the Classroom JPA object into the SchoolUser object - since these two objects don't have a direct relationship.
Any way that I can accomplish this with JPA?
If you do not want to persist the classroom (or any other attribute for that matter) then the #Transient annotation allows you to ignore a particular field so that JPA won't try to map it.
This annotation specifies that the property or field is not
persistent. It is used to annotate a property or field of an entity
class, mapped superclass, or embeddable class.
Example:
#Entity
public class Employee {
#Id int id;
#Transient User currentUser;
...
}

Categories

Resources