EntityManager createQuery with single column throws type error - spring

I am using LocalContainerEntityManagerFactoryBean and OracleUCPConfig
I have class EmployeeEntity.java mapped to table employee
I have written a createQuery code as
Query query = em.createQuery("select id from Employee", EmployeeEntity.class);
query.getResultList()
I am getting error as:
Type specified for TypedQuery [EmployeeEntity] is incompatible with [java.lang.String]
how do I solve this issue?
I want all ids from the table not any other fields needs to retrieved
--EDIT--
I solved the issue by change the JQL to JPQL
Query query = em.createQuery("select new EmployeeEntity(id) from Employee", EmployeeEntity.class);
query.getResultList()

you are mapping id to type EmployeeEntity, if you check your query, you are extracting only id instead of everything: select id from Employee. you can fix this by changing your query to:
Query query = em.createQuery("select e from Employee e", EmployeeEntity.class);
if you need only id column you could do something like:
TypedQuery<String> query = em.createQuery("select e.id from Employee e", String.class);
List<String> ids = query.getResultList();

The second parameter of createQuery() is the type of the query result. In your case, the result type is String (a list of Strings), as you only SELECT the column id.
So this should work:
Query query = em.createQuery("select e.id from Employee e", String.class);
List<String> ids = query.getResultList();

Related

JPA nativeQuery with UNION does not support pagination

Consider the following tables:
TABLE A
id
sys_time
user_id
rent_time
TABLE B
id
sys_time
occur_time
I would like to use a UNION query in MYSQL to have this table and put data from both tables row by row with sys_time order:
TABLE AB
id
sys_time
user_id
occur_time
rent_time
I use the following query:
select id, sys_time, user_id, null as occur_time, rent_time from open_close
union
select id, sys_time, null as user_id, occur_time, null as rent_time from periodic
order by sys_time desc;
Now I define an #Entity with the following structure:
...
#Data
#Entity
#NamedNativeQuery(
name="TotalEntity.getTotal"
, query="select id, sys_time, user_id, null as occur_time, rent_time from open_close\r\n"
+ "union\r\n"
+ "select id, sys_time, null as user_id, occur_time, null as rent_time from periodic \r\n" + "order by sys_time desc;"
, resultClass=TotalEntity.class
)
...
// Entity Fields and so on
and the corresponding Repository:
#Repository
public interface TotalRepository extends JpaRepository<TotalEntity, BigInteger> {
#Query(nativeQuery = true)
public List<TotalEntity> getTotal();
}
Everything is OK up to now.
Now I want to add pagination:
#Repository
public interface TotalRepository extends JpaRepository<TotalEntity, BigInteger> {
#Query(nativeQuery = true)
public Page<TotalEntity> getTotal(Pageable page);
}
and use this:
...
private TotalRepository tr;
...
Pageable pageable = PageRequest.of(page, size,
direction.toUpperCase().equals("ASC") ? Sort.by(sort).ascending() : Sort.by(sort).descending());
Optional<Page<TotalEntity>> pe = Optional.ofNullable(tr.getTotal(pageable));
The following exception is thrown:
java.sql.SQLSyntaxErrorException: 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 'limit 20' at line 4
It seems that Hibernate can not modify the nativeQuery to add pagination statements. And I know that JPQL and JPA does not supprt UNIONs. Is there any workaround for this?
A workaround would be to introduce a view in the database layer with the union clause, and then execute the query upon the view.
This way, you can hide the union from JPA layer and queries can be executed using pageable as usual.
CREATE VIEW view_name AS
select id, sys_time, user_id, null as occur_time, rent_time from open_close
union
select id, sys_time, null as user_id, occur_time, null as rent_time from periodic
And modify the JpaRepository to query upon the view using prefered way, like native queries, column projections etc.
If you are not planning to use other functionalities from Pageable interface like getting the total records count, number of current slice etc., then try using offset and limit keywords in the query directly for the pagination.
Note : offeset corresponds to page and limit corresponds to size of content in the page

Problem with MongoDB #Query annotation/Query

I got problems with #Query annotation or Query query = new Query() - I can't include/exclude some fields.
I find code samples like:
#Query(value = "{'id': ?0}",fields = "{'id':1}")
User findUserById(String id);
Result should be user with only one field -> id but its showing other fields to..
So I found other samples like:
Query query = new Query();
query.fields().include("id");
query.addCriteria(Criteria.where("id").is(id));
User one = mongoTemplate.findOne(query, User.class);
Same result there..
Any ideas?
Integer findUserById(String id);
Use the DataType of Id [like Integer] to get only id.
Change datatype of according the requirement/usecase

Partial update without retrieving the object from db

I am looking for some way to partially update an object without retrieving the object from DB.
Say I have an Employee entity containing the following properties -
firstName
lastName
phone
age
salary
The JSON I get in the update request may not contain all the properties. I need to make sure I update only the properties provided in the request and leave all other data unchanged.
I explored some ways of achieving partial update but all of them involves retrieving the data from db. I don't have this option since the db in my case is too slow and this will increase the response time. Please suggest
You can combine #Modifying and #Query annotation to issue an update query
#Modifying
#Query("update Employee e set e.firstName = :firstName, e.lastName = :lastName where e.id = :id")
void updateEmployeePartially(Long id, String firstName, String lastName);
For more information, you can check this article

How to replace SQL Query CONDITION in Spring JPA native query

I have a spring jpa native query(actual query has multiple tables connected) something like below.
#Query(nativeQuery = true, value="
select id, name from TABLE where id NOT IN ('2', '3')")
List<Object> getValueForNOTIN()
#Query(nativeQuery = true, value="
select id, name from TABLE where id IN ('4', '5')")
List<Object> getValueForIN()
Instead of 2 methods, I want to use one method which replaces NOT IN and IN with this 'replaceClause' value.
List<Object> getValueForBoth(#Param("replaceClause)" String replaceClause)
I get error on start of server. Can't I do like this?
You can use a static string like
private String SELECT_NOT_IN_QUERY = "select id, name from TABLE
where id NOT IN ('id1', 'id2')"
private String SELECT_IN_QUERY = "select id, name from TABLE
where id IN ('id1', 'id2')"
then look for id1 and id2 and replace with its values. use the right static string accordingly.

Spring-Data JPA: How to make a jpa criteria query

Given this two entities:
post post_category
- id - post_id
- title - name
- text
I'd like to make this query using jpa criteria query:
select * from post
where post.id in (
select post_id from post_category
where name = '<category1>' and name = '<category2>' ... and name = '<categoryN>')
Looking at your query sketch I think it will not return any results. I have changed it to mean name in ('<category1>','<category2>', ...) instead. Which may not match your case.
This assumes that you have your mapping set up properly on your classes for JPA to work. For example
class PostCategory {
private String name;
private Post post;
...
#ManyToOne
public Post getPost() {
return post;
}
...
In which case your DAO code would resemble this (given a List nameValues object)
// Set up the subquery
DetachedCriteria dc = DetachedCriteria.forClass(PostCategory.class)
.setProjection(Projections.property("post.id"))
.add(Restrictions.in("name", nameValues));
Criteria crit = session.createCriteria(Post.class)
.add(Subqueries.eqProperty("id", dc));
But if you want a list of Post objects which have ALL of the categories then you will need to make a separate DetachedCriteria instance for each category and add each as an AND'ed Subquery.

Resources