Spring data - JPA : issue query with DTO and IF statement - java

I am trying to make a query that would build a DTO object :
#Query("Select new com.mycorp.rh.web.rest.dto.AnalyseProductionDTO(a.client.name, IF(a.salarie,'yes','no'))
from Activity a where a.year = ?1 and a.month = ?2")
List<AnalyseProductionDTO> getAnalyseProduction(Year year, Month month);
It doesn't work when I put a IF statement in the query.
I am getting a
java.lang.IllegalArgumentException: Validation failed for query
It works when I do :
#Query("Select new com.mycorp.rh.web.rest.dto.AnalyseProductionDTO(a.client.name, 'yes')
from Activity a where a.year = ?1 and a.month = ?2")
List<AnalyseProductionDTO> getAnalyseProduction(Year year, Month month);
Isn't it possible to include an IF statement in a constructor used in a query?

By default #Query doesn't allow native queries. The query should be either HQL if the ORM is hibernate or anything that is supported by the underlying ORM.
Since IF() function is native to MySQL and not supported by ORM query languages its validation will fail.
You can try the following with #Query.nativeQuery set to true.
#Query(value = "Select new com.mycorp.rh.web.rest.dto.AnalyseProductionDTO(a.client.name, IF(a.salarie,'yes','no'))
from Activity a where a.year = ?1 and a.month = ?2", nativeQuery = true)

Related

dynamic Query in #Query annotation

I have situation in which I have to compose a JPQL query in some method, then pass this query to spring data query method to be used as the query in #Query annotation.
#Query(value = ":DyanamicQuery")
List<PrizeInsuranceConfiguration> filterConfigurPrizeInsurance(String DyanamicQuery);
This is not possible. As it throws compile error. Can you give me an alternat way to achieve this?
#Query(value = ":DyanamicQuery")
List<PrizeInsuranceConfiguration> filterConfigurPrizeInsurance(String DyanamicQuery);
expected to get Query that I made will go and sit at value = ":DyanamicQuery" I also tried giving #Query("#{#entityName}").
You can create a JPQL query as a string, but you cannot pass it as a parameter to the value attribute of the #Query annotation.
You can use below example -
String dyanamicQuery= "SELECT * FROM table_name WHERE condition= :condition";
#Query(value = dyanamicQuery)
List<Entity> findByField(#Param("condition") String condition);
Or you can use below example also -
#Query(value = "SELECT * FROM table_name WHERE condition= :condition")
List filterConfigurPrizeInsuranceByField(#Param("condition") String condition);

Named parameter not bound criteria native query [duplicate]

I want to execute a simple native query, but it does not work:
#Autowired
private EntityManager em;
Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = :username");
em.setProperty("username", "test");
(int) q.getSingleResult();
Why am I getting this exception?
org.hibernate.QueryException: Not all named parameters have been set: [username]
Named parameters are not supported by JPA in native queries, only for JPQL. You must use positional parameters.
Named parameters follow the rules for identifiers defined in Section 4.4.1. The use of named parameters applies to the Java Persistence query language, and is not defined for native queries. Only positional parameter binding may be portably used for native queries.
So, use this
Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");
While JPA specification doesn't support named parameters in native queries, some JPA implementations (like Hibernate) may support it
Native SQL queries support positional as well as named parameters
However, this couples your application to specific JPA implementation, and thus makes it unportable.
After many tries I found that you should use createNativeQuery And you can send parameters using # replacement
In my example
String UPDATE_lOGIN_TABLE_QUERY = "UPDATE OMFX.USER_LOGIN SET LOGOUT_TIME = SYSDATE WHERE LOGIN_ID = #loginId AND USER_ID = #userId";
Query query = em.createNativeQuery(logQuery);
query.setParameter("userId", logDataDto.getUserId());
query.setParameter("loginId", logDataDto.getLoginId());
query.executeUpdate();
You are calling setProperty instead of setParameter. Change your code to
Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = :username");
em.setParameter("username", "test");
(int) q.getSingleResult();
and it should work.
I use EclipseLink. This JPA allows the following way for the native queries:
Query q = em.createNativeQuery("SELECT * FROM mytable where username = ?username");
q.setParameter("username", "test");
q.getResultList();
Use set Parameter from query.
Query q = (Query) em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");
This was a bug fixed in version 4.3.11
https://hibernate.atlassian.net/browse/HHH-2851
EDIT:
Best way to execute a native query is still to use NamedParameterJdbcTemplate
It allows you need to retrieve a result that is not a managed entity ; you can use a RowMapper and even a Map of named parameters!
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
final List<Long> resultList = namedParameterJdbcTemplate.query(query,
mapOfNamedParamters,
new RowMapper<Long>() {
#Override
public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getLong(1);
}
});

Hibernate not Injecting Parameters in Query Annotation

I've read the documentation on inserting method parameters into queries and other questions however they all suggest that this should work.
#Query(value = "SELECT * FROM period WHERE time LIKE \":day%\" AND id IN (SELECT id FROM booking)", nativeQuery = true)
List<Booking> findAllBookingsOnDay(#Param("day") String day);
Results in:
Hibernate: SELECT * FROM period WHERE time LIKE ":day%" AND id IN (SELECT id FROM booking)
I've tried removing quotations and percentage but that just results in.
Hibernate: SELECT * FROM period WHERE time LIKE ? AND id IN (SELECT id FROM booking)
The correct way to do this is to just use an unescaped placeholder in the query, and the bind the LIKE wildcard expression to it from the Java side.
#Query(value = "SELECT * FROM period WHERE time LIKE :day AND id IN (SELECT id FROM booking)", nativeQuery =true)
List<Booking> findAllBookingsOnDay(#Param("day") String day);
Usage:
String day = "%friday%"; // or whatever value would make sense here
findAllBookingsOnDay(day);

Dyamic table name for JPQL / Hibernate query

I've a database with many thousands of tables that have been (and continue to be) created with a naming strategy - one table per calendar day:
data_2010_01_01
data_2010_01_02
...
data_2020_01_01
All tables contain sensor data from the same system in the same shape. So a single entity (lets call it SensorRecord) will absolutely map to all tables.
I'd imagined something like this would work:
#Query(nativeQuery = true, value = "SELECT * FROM \"?1\"")
Collection<SensorRecord> findSensorDataForDate(String tableName);
But it does not, and reading around the topic seems to suggest I am on the wrong path. Most posts on dynamic naming seem to state explicitly that you need one entity per table, but generating thousands of duplicate entities also seems wrong.
How can I use JPA (JPQL?) to work with this data where the table name follows a naming convention and can be changed as part of the query?
Parameters are only allowed in the where clause.
You can create custom repository method returns collection of SensorRecord dto. No need to map so many entities. You should get List<Object []> as query result and manually create dto objects.
#Autowired
EntityManager entityManager;
public List<SensorRecord> findSensorDataForDate(LocalDate date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd");
String tableName = "data_" + date.format(formatter);
Query query = entityManager.createNativeQuery(
"select t.first_column, t.second_column from " + tableName + " t");
List<Object[]> queryResults = query.getResultList();
List<SensorRecord> sensorRecords = new ArrayList<>();
for (Object[] row : queryResults) {
SensorRecord record = new SensorRecord();
record.setFirstParameter((Integer) row[0]);
record.setSecondParameter((String) row[1]);
sensorRecords.add(record);
}
return sensorRecords;
}
Could it be just syntax error?
This has worked for me:
#Query(value = "select * from job where job.locked = 1 and job.user = ?1", nativeQuery = true)
public List<JobDAO> getJobsForUser(#Param("user") String user);

Select top 1 result using JPA

I need to bring from DB only one single result. How can I do that with JPA?
Select top 1 * from table
I tried
"select t from table t"
query.setMaxResults(1);
query.getSingleResult();
but didn't work. Any other ideas?
Try like this
String sql = "SELECT t FROM table t";
Query query = em.createQuery(sql);
query.setFirstResult(firstPosition);
query.setMaxResults(numberOfRecords);
List result = query.getResultList();
It should work
UPDATE*
You can also try like this
query.setMaxResults(1).getResultList();
To use getSingleResult on a TypedQuery you can use
query.setFirstResult(0);
query.setMaxResults(1);
result = query.getSingleResult();
2021 att: you can use TOP or FIRST in Spring Data JPA
example:
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
doc: https://docs.spring.io/spring-data/jpa/docs/2.5.4/reference/html/#repositories.limit-query-result
The easiest way is by using #Query with NativeQuery option like below:
#Query(value="SELECT 1 * FROM table ORDER BY anyField DESC LIMIT 1", nativeQuery = true)
Use a native SQL query by specifying a #NamedNativeQuery annotation on the entity class, or by using the EntityManager.createNativeQuery method. You will need to specify the type of the ResultSet using an appropriate class, or use a ResultSet mapping.

Categories

Resources