I am getting an exception while trying to fetch some data using HQL with parameters. Below is the exception and the code.
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: TESTDB.ORDER_DETAILS is not mapped [SELECT DATE,ORDER_NAME,DESCRIPTION FROM TESTDB.ORDER_DETAILS WHERE ORDER_ID = :orderId ORDER BY DATE DESC]
//*************************************************************
OrderDetailDTO orderDetailDTO = new OrderDetailDTO();
List<OrderDetailDTO> orderList = new ArrayList<OrderDetailDTO>();
ResultSet rs = null;
String queryStr = "SELECT DATE,ORDER_NAME,DESCRIPTION "
+ "FROM TESTDB.ORDER_DETAILS WHERE ORDER_ID = :orderId "
+ "ORDER BY DATE DESC";
org.hibernate.query.Query query = session.createQuery(queryStr).setParameter("orderId", ordId);
rs = (ResultSet)query.getResultList();
while(rs.next()!=false){
orderDetailDTO.setOrderName(rs.getString("ORDER_NAME"));
orderDetailDTO.setDescription(rs.getString("DESCRIPTION"));
orderDetailDTO.setDate(rs.getTimestamp("DATE"));
orderList.add(orderDetailDTO);
}
//*************************************************************
//ordId : This one I have as argument in the method
I have to use this parameterised HQL to avoid SQL injection. Can anyone figure out why the weird error of IllegalArgumentException is comming.
The solution is done by using the entity names instead of the database table names. There is the catch. In JPQL we need to use the java bean class name in the query. When I replaced the java bean class name with the java bean fields name everything worked fine.
Also in JPQL mentioning the schema name is not required as in case of JPQL hibernate will use the schema
as defined by the hibernate.default_schema configuration property. The URL used for reference is https://vladmihalcea.com/how-to-resolve-the-hibernate-global-database-schema-and-catalog-for-native-sql-queries/
Below is the working code :
The java code for the database table :
package demo.jpql;
import java.io.Serializable;
import javax.persistence.*;
import java.sql.Timestamp;
#Entity
#Table( name = "ORDER_DETAILS" )
public class OrderDetails implements Serializable {
private static final long serialVersionUID = 1L;
#Column( name = "ORDER_NAME", length = 50 )
private String orderName;
#Column( name = "DESCRIPTION", length = 50 )
private String desc;
#Column( name = "DATE" )
private Timestamp date;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Timestamp getDate() {
return date;
}
public void setDate(Timestamp date) {
this.date = date;
}
}
//*************************************************************
OrderDetailDTO orderDetailDTO = new OrderDetailDTO();
List<OrderDetailDTO> orderList = new ArrayList<OrderDetailDTO>();
ResultSet rs = null;
String queryStr = "SELECT date,orderName,desc"
+ "FROM OrderDetails WHERE orderID =:orderId "
+ "ORDER BY date DESC";
org.hibernate.query.Query query =
session.createQuery(queryStr).setParameter("orderId", ordId);
List<Object> rsltLstOrderDtls = (List<Object>)query.getResultList();
Iterator<Object> itr = rsltLstOrderDtls.iterator();
while (itr.hasNext()) {
Object[] obj = (Object[]) itr.next();
orderDetailDTO.setOrderName(String.valueOf(obj[1]));
orderDetailDTO.setDescription(String.valueOf(obj[2]));
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
java.util.Date parsedDate = dateFormat.parse(String.valueOf(obj[0]));
Timestamp timestamp = new java.sql.Timestamp(parsedDate.getTime());
orderDetailDTO.setDate(timestamp);
orderList.add(orderDetailDTO);
}
//*************************************************************
Related
I am creating a Spring web application that queries SPARQL endpoints. As a requirement, I'm supposed to save the query and the result for later viewing and editing. So far I have created some entities (QueryInfo, Result, Endpoint) that I use to save the information entered about the Query and the Result. However I'm having trouble with saving the actual results themselves
public static List<String> getSelectQueryResult(QueryInfo queryInfo){
Endpoint endpoint = queryInfo.getEndpoint();
Query query = QueryFactory.create(queryInfo.getContent());
List<String> subjectStrings = query.getResultVars();
List<String> list = new ArrayList();
RDFConnection conn = RDFConnectionFactory.connect(endpoint.getUrl());
QueryExecution qExec = conn.query(queryInfo.getContent()) ; //SELECT DISTINCT ?s where { [] a ?s } LIMIT 100
ResultSet rs = qExec.execSelect() ;
while (rs.hasNext()) {
QuerySolution qs = rs.next();
System.out.println("qs: "+qs);
RDFNode rn = qs.get(subjectStrings.get(0)) ;
System.out.print(qs.varNames());
if(rn!= null) {
if (rn.isLiteral()) {
Literal literal = qs.getLiteral(subjectStrings.get(0));
list.add(literal.toString());
} else if (rn.isURIResource()) {
Resource subject = qs.getResource(subjectStrings.get(0));
System.out.println("Subject: " + subject.toString());
list.add(subject.toString());
}
}
}
return list;
}
My Result entity looks like this:
#Entity #Data #Table(schema = "sparql_tool") public class Result {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(length = 10485760)
private String content;
#OneToOne
#JoinColumn(name = "query_info_id",referencedColumnName = "id")
private QueryInfo queryInfo;
#Column(length = 10485760)
#Convert(converter = StringListConverter.class)
private List<String> contentList;
public Result() {
}
public Result(String content, QueryInfo queryInfo, List<String> list) {
this.content = content;
this.queryInfo = queryInfo;
this.contentList=list;
}
}
I used to save the actual results in the List contentList attribute. However, this only works when the query has only one result variable. If I have multiple result variables I have a table instead of a list. What is the best way to save this result in DB?
I'm working with an SQL DB if that is relevant. Thank you so much in advance!
I am trying to figure out mickito test for Named Jdbc Template but unable to do so. I did googling but did not find any accurate result. Below is example Code.
Student.class
#Data
public class Student {
private int id;
private String name;
private String address;
public Student(ResultSet rs) throws SQLException {
id = rs.getInt("id");
name = rs.getString("name");
address = rs.getString("address");
}
}
Student class takes ResultSet argument in constructor and mapped all column to variable .
StudentService.class
public class StudentService {
#Autowired
#Qualifier("namedJdbcTemplate")
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public Student gerStudent(String id) {
Student student;
String selectStudent = "select id , name ,address from student where id=:id";
MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();
mapSqlParameterSource.addValue(id, "id");
student = namedParameterJdbcTemplate.query(selectStudent, mapSqlParameterSource, resultSet -> {
Student response = new Student(resultSet);
return response;
});
return student;
}
}
Can anyone please help on Mockito Test for below line of code?
student = namedParameterJdbcTemplate.query(selectStudent, mapSqlParameterSource, resultSet -> {
Student response = new Student(resultSet);
return response;
});
Is it correct to write JUnit test case for Repository like this? Also while running it , Iam getting NullPointerException at line Mockito.when...
here is my test class:
#ContextConfiguration(locations = { "classpath*:resources/invoices-context.xml",
"classpath*:resources/invoices-int-schema.xml" })
public class RoomRepositoryTest {
#Autowired
RoomRepository roomRepository;
private RoomEntity roomEntity;
#Test
public void findRommByDateTest() throws ParseException {
String startDate = "27-07-2020";
sDate = new SimpleDateFormat("dd-mm-yyyy").parse(startDate);
String endDate = "28-07-2020";
eDate = new SimpleDateFormat("dd-mm-yyyy").parse(endDate);
String roomType = "SINGLE";
roomEntity = new RoomEntity();
roomEntity.setRoomId(1);
roomEntity.setRoomPrice(6000);
roomEntity.setRoomStatus("AVAILABLE");
roomEntity.setRoomType("SINGLE");
Mockito.when(
roomRepository.findRoomByDate(Mockito.any(Date.class), Mockito.any(Date.class), Mockito.anyString()))
.thenReturn(roomEntity.getRoomId());
int id = roomRepository.findRoomByDate(Mockito.any(Date.class), Mockito.any(Date.class), Mockito.anyString());
assertEquals(1, id);
}
}
Instead of mocking the database fetch function, you can just use the embedded database setup with some annotations. It helps us to test the query efficiently. If you are using an in-memory database(embedded) first you have to add (save) entry in the table. Then your query function should fetch the data. With the help of this you can easily debug the null pointer exceptions.
Eg:
#SpringBootTest
#AutoConfigureTestDatabase
#ContextConfiguration(locations = { "classpath*:resources/invoices-context.xml",
"classpath*:resources/invoices-int-schema.xml" })
public class RoomRepositoryTest {
#Autowired
RoomRepository roomRepository;
private RoomEntity roomEntity;
#Test
public void findRommByDateTest() throws ParseException {
String startDate = "27-07-2020";
sDate = new SimpleDateFormat("dd-mm-yyyy").parse(startDate);
String endDate = "28-07-2020";
eDate = new SimpleDateFormat("dd-mm-yyyy").parse(endDate);
String roomType = "SINGLE";
roomEntity = new RoomEntity();
roomEntity.setRoomId(1);
roomEntity.setRoomPrice(6000);
roomEntity.setRoomStatus("AVAILABLE");
roomEntity.setRoomType("SINGLE");
//adding data for testing
roomRepository.save(roomEntity)
//test the actual function
int id = roomRepository.findRoomByDate(sDate,eDate);
assertEquals(1, id);
}
I have two models:
#Entity
public class Product{
#Id
private String ProductID;
private String ProductName;
#ManyToOne
#JoinColumn
private Supplier supplier;
private int quantity;
private int price;
//getter setter...
//constructor...
}
#Entity
public class Supplier {
#Id
private String SupplierID;
private String SupplierName;
private String Phone;
private String Address;
private String Email;
//getter setter
//constructor
}
In jdbc template of spring i can get all record i want like this:
public List<Product> getProducts(int take, int skip){
List<Product> list = new ArrayList<Product>();
String sql = "SELECT product.ProductID, product.ProductName, product.Quantity, supplier.SupplierID"
+ ", supplier.SupplierName, product.Price"
+ " FROM product INNER JOIN supplier ON product.SupplierID = supplier.SupplierID"
+ " LIMIT " + skip + "," + take + "";
list = jdbcTemplate.query(sql, new ProductMapper());
return list;
public class ProductMapper implements RowMapper<Product> {
public Product mapRow(ResultSet rs, int line) throws SQLException {
Product product = new Product();
product.setProductID(rs.getString("ProductID"));
product.setProductName(rs.getString("ProductName"));
product.setQuantity(rs.getInt("Quantity"));
product.setSupplier(new Supplier(rs.getString("SupplierID"), rs.getString("SupplierName")));
product.setPrice(rs.getInt("Price"));
return product;
}
But it's wrong in hibernate:
//--------hibernate-------
Session session = sessionFactory.openSession();
session.beginTransaction();
String queryStr = "SELECT Product.ProductID, Product.ProductName, Product.Quantity, Supplier.SupplierID"
+ ", Supplier.SupplierName, Product.Price"
+ " FROM Product INNER JOIN Supplier ON Product.SupplierID = Supplier.SupplierID";
List<Product> list = new ArrayList<Product>();
try {
Query query = session.createQuery(queryStr);
query.setFirstResult(skip);
query.setMaxResults(take);
list = (List<Product>) query.list();
session.getTransaction().commit();
}
catch(Exception e) {
System.out.println("Exception e" + e);
session.getTransaction().rollback();
}
finally {
session.close();
}
return list;
}
i get "path expected for join" and Exception eorg.hibernate.QueryException: Unable to resolve path [Product.ProductID], unexpected token [Product] [SELECT Product.ProductID .... ]
Anyone can help me to get the same result when i do with jdbc template.
SELECT p.ProductID, p.ProductName, p.Quantity, s.SupplierID, s.SupplierName, p.Price
FROM Product p
INNER JOIN p.Supplier s
You need to use paths in your HQL query, from one entity to the other. The Hibernate documentation on HQL and joins provides more information here.
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#queryhql-joins
String sql = "SELECT product.ProductID, product.ProductName,
product.Quantity, supplier.SupplierID"
+ ", supplier.SupplierName, product.Price"
+ " FROM product INNER JOIN supplier ON product.SupplierID = supplier.SupplierID"
+ " LIMIT " + skip + "," + take + "";
If you are using sql query then you need to give SQL table and sql table columns,
But here you are mixing SQL table and Java Classes , like
product is probably a SQL table and Product is the entity class.
So change your query as
String sql = "SELECT p.ProductID, p.ProductName, p.Quantity, s.SupplierID"
+ ", s.SupplierName, s.Price"
+ " FROM Product p INNER JOIN Supplier s ON p.SupplierID = s.SupplierID"
+ " LIMIT " + skip + "," + take + "";
Also, your variable names are not in camelCase, this can mess up Hibernate's way of mapping a Entity property to table columns, so pay special attention to getter and setters .
I am facing two issues here :
Issue 1) I am trying to get the COMPANY_ID using the selectCompanyID variable as shown below. I am storing the value returned into getCompanyID variable.When I tried to print it, as shown in the console output below, it's always printing number 1. However, when I tried to run the actual SQL in the
Oracle SQL developer SQL Worksheeet, I got different number. Because of this I could insert wrong ID in the following INSERT statement where it's
getting used.
Issue 2) As shown in the SQL, I am also getting ORA-00984: column not allowed here error. Noticed, people encountering similar error in the following post :
"column not allowed here" error in INSERT statement
But here I don't have straightforward SQL INSERT statement as the one mentioned in the above post with missing quotes.
public boolean insertEmployeeDetails(Employee employee)
{
logger.debug("Starting EmployeeDaoImpl.insert() .....");
Session session = null;
Transaction tx = null;
boolean status = true;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
//The following SELECT query returns a number when I ran it in the Oracle SQL developer SQL worksheet
String selectCompanyID = "SELECT"
+ " VALUE_EMP_ID"
+" FROM "
+ " COMPANY_DATA"
+" WHERE"
+ " testing_id = 1234"
+" AND "
+ " company_employee_id = 3345";
int getCompanyID = session.createSQLQuery(selectCompanyID)
.executeUpdate();
System.out.println("GetCompanyID Test below");
System.out.println(getCompanyID);
String hqlInsert = "INSERT INTO Employee (NAME, IS_CORRECT,IS_WRONG,COMPANY_ID, TRANSACTION_ID,DEFINITION) VALUES"
+ "( SELECT value_emp_id FROM COMPANY_DATA WHERE testing_id = 1234 AND"
+ " company_employee_id = 3345))";
String hqlInsert = "INSERT INTO Employee (NAME,IS_CORRECT,IS_WRONG,COMPANY_ID,TRANSACTION_ID,DEFINITION) VALUES "
+ "("
+employee.getName()+","
+employee.getIsCorrect()+","
+employee.getIsWrong()+","
+getCompanyID+","
+employee.getTransactionId()+","
+employee.getDefinition()+")";
System.out.println("October 3 Checking for hqlInsert");
System.out.println(hqlInsert);
int createdEntities = session.createSQLQuery( hqlInsert )
.executeUpdate();
session.persist(employee);
tx.commit();
System.out.println("October 3 BELOW Checking for hqlInsert");
System.out.println(hqlInsert);
System.out.println("Checking for CreatedEntities");
System.out.println(createdEntities);
} catch(Exception ex) {
tx.rollback();
ex.printStackTrace();
status = false;
} finally {
session.close();
}
logger.debug("Completed EmployeeDaoImpl.insert() .....");
return status;
}
Console :
Hibernate:
SELECT
VALUE_EMP_ID
FROM
COMPANY_DATA
WHERE
testing_id = 1234
AND company_employee_id = 3345
GetCompanyID Test below
1
October 3 Checking for hqlInsert
INSERT INTO Employee (NAME,IS_CORRECT,IS_WRONG,COMPANY_ID,TRANSACTION_ID,DEFINITION) VALUES (Terminology,0,0,1,0,definitionTest)
Hibernate:
INSERT
INTO
Employee
(NAME,IS_CORRECT,IS_WRONG,COMPANY_ID,TRANSACTION_ID,DEFINITION)
VALUES
(Terminology,0,0,1,0,definitionTest)
2017-10-03 11:32:43.753 WARN 5392 --- [nio-8080-exec-4] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 984, SQLState: 42000
2017-10-03 11:32:43.753 ERROR 5392 --- [nio-8080-exec-4] o.h.engine.jdbc.spi.SqlExceptionHelper : ORA-00984: column not allowed here
Here is my Entity Class Employee.java is as follows:
package abc.def.mypackage.orm
#Entity
#Table(name = "EMPLOYEE")
public class Employee {
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIsCorrect() {
return isCorrect;
}
public void setIsCorrect(int isCorrect) {
this.isCorrect = isCorrect;
}
public int getIsWrong() {
return isWrong;
}
public void setIsWrong(int isWrong) {
this.isWrong = isWrong;
}
public int getCompanyId() {
return companyId;
}
public void setCompanyId(int companyId) {
this.companyId = companyId;
}
public Integer getTransactionId() {
return transactionId;
}
public void setTransactionId(Integer transactionId) {
this.transactionId = transactionId;
}
public String getDefinition() {
return definition;
}
public void setDefinition(String definition) {
this.definition = definition;
}
#Id
#Column(name = "EMPLOYEE_ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "seqgen")
#SequenceGenerator(name = "seqgen", sequenceName = "EMPLOYEE_AUTOINC_SEQ")
private int employeeId;
#Column(name = "NAME")
private String name;
#Column(name = "DEFINITION")
private String definition;
#Column(name = "IS_CORRECT")
private int isCorrect;
#Column(name = "IS_WRONG")
private int isWrong;
#Column(name = "COMPANY_ID")
private int companyId;
#Column(name = "TRANSACTION_ID", nullable = true)
private Integer transactionId;
}
Try putting your String values employee.getName() and employee.getDefinition() in your insert statement into quotes '
String hqlInsert = "INSERT INTO Employee (NAME,IS_CORRECT,IS_WRONG,COMPANY_ID,TRANSACTION_ID,DEFINITION) VALUES "
+ "('"
+employee.getName()+"',"
+employee.getIsCorrect()+","
+employee.getIsWrong()+","
+getCompanyID+","
+employee.getTransactionId()+",'"
+employee.getDefinition()+"')";