#NamedNativeQuery - How can I bind it to a repository method? - java

I am using Spring + Hibernate and I have a particular case where I need to obtain (a list of) non-Entity objects as a result of the query.
I decided to use #ConstructorResult in #SqlResultSetMapping and refer to this mapping in #NamedNativeQuery, as mentioned here and here.
However, in all examples using named native queries, they obtain EntityManager instance via #PersistenceContext and call createNativeQuery on it, providing the name of #NamedNativeQuery as parameter to that call, as seen in this answer.
How can I map a method declared in a repository interface to a particular #NamedNativeQuery? My attempt was to use EntityName.MethodNameInRepository or MethodNameInRepository as the name of #NamedNativeQuery, but no luck.
Here is my simplified code:
#Entity(name = "AdDailyData")
#SqlResultSetMapping(
name="RevenueByAppAndDayMapping",
classes=#ConstructorResult(
targetClass=RevenueByAppAndDay.class,
columns={#ColumnResult(name="country_code"),
#ColumnResult(name="revenue", type=Double.class),
#ColumnResult(name="currency")}))
#NamedNativeQuery(
name="AdDailyData.aggregateRevenue",
query="SELECT country_code, sum(earnings) as revenue, currency "
+ "FROM ad_daily_data, pseudo_app, app "
+ "WHERE ad_daily_data.pseudo_app_id=pseudo_app.id AND pseudo_app.app_id=app.id AND app.id=:appId and ad_daily_data.day = :day "
+ "GROUP BY country_code, currency "
+ "ORDER BY country_code ASC",
resultSetMapping="RevenueByAppAndDayMapping")
public class AdDailyDataEntity {
// fields, getters, setters etc.
public static interface Repository extends JpaRepository<AdDailyDataEntity, Long> {
public List<RevenueByAppAndDay> aggregateRevenue(#Param("appId") long appId, #Param("day") LocalDate day);
}
}
Here is my non-Entity class.
public class RevenueByAppAndDay {
private String countryCode;
private Double earnings;
private String currency;
public RevenueByAppAndDay(String countryCode, Double earnings, String currency) {
this.countryCode = countryCode;
this.earnings = earnings;
this.currency = currency;
}
public String getCountryCode() {
return countryCode;
}
public Double getEarnings() {
return earnings;
}
public String getCurrency() {
return currency;
}
}
Any kind of help is highly appreciated.
EDIT:
The end of the stack trace is as follows:
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property aggregateRevenue found for type AdDailyDataEntity!

The name value on the #NamedNativeQuery needs to be set to "AdDailyDataEntity.aggregateRevenue". The first part (before the dot) needs to match the entity class name.

Although the answer is correct, for someone to arrived here for similar cuestions this works for me without used #NamedNativeQuery:
public class Example {
private Long someProperty;
// getters and setters
}
To call a query or stored procedure and populate my object:
#Repository
public interface ExampleRepository extends
JpaRepository<Example,Long> {
/**
* Search Example by someProperty
*
* #param property
* #return
*/
#Query( nativeQuery = true, value = "SELECT * FROM public.my_stored_procedure(:property)")
List<Example> findByProperty(#Param("property") Long property);
}
I know this is another approach and the code is decoupled, but we get the same result.
I hope that can be useful for someone.
Regards.

Related

Is it possible to use JpaRepository without entity?

Is it possible to use JpaRepository without entity? In this case, replacing it with a DTO.
as follows the example
#Repository
public interface BffRepository extends JpaRepository<BffDTO, String> {
#Query(nativeQuery = true, value = "select\n"
+ "ent.name as enterprise_name, dep.name as department_name,\n"
+ "sq.name as squad_name, acc.firstname as job_owner_name,\n"
+ "tpt.name as test_template_name, job.name, job.job_blocked, job.job_removed,\n"
+ "job.bot_scm_branch, job.bot_scm_url, job.schedule_startdate,\n"
+ "job.expiration_date, job.timestamp,job.uuid,job.schedule_starttime,\n"
+ "tpt.job_execution_timeout\n"
+ "from portal.jobs job\n"
+ "left join portal.enterprises ent on (ent.uuid = job.enterprise_id)\n"
+ "left join portal.departments dep on (dep.uuid = job.department_id)\n"
+ "left join portal.squads sq on (sq.uuid = job.squad_id)\n"
+ "left join portal.accounts acc on (acc.uuid = job.job_owner)\n"
+ "left join portal.test_plan_templates tpt on (tpt.uuid = job.template_id) where\n"
+ "job.job_owner = ?1 and job.job_removed = false order by timestamp desc;")
List<BffDTO>buscarPorJobOwner(String jobOwner);
Are there alternatives for this case?
NOTE: the DTO is already mapped, but I would not like to create a view to transform this DTO into an Entity.
I already validated this topic, but without major advances
Use JpaRepository interaction style without entity
i'm trying this
Interface -
public interface BffDTOInterface2 {
String uuid();
String enterprise_name();
String department_name();
String squad_name();
String job_owner_name();
String test_template_name();
String name();
Boolean job_blocked();
Boolean job_removed();
String bot_scm_branch();
String bot_scm_url();
String schedule_startdate();
String expiration_date();
String timestamp();
String schedule_starttime();
Integer job_execution_timeout();
#Transient
String status();
}
I'm having this error
Caused by: java.lang.IllegalArgumentException: Not a managed type: interface br.com.cloud.api.domain.dto.BffDTOInterface2
You can use Projections based on interfaces.
e.g
Create your native-query givin it column a alias. select name as fullName, age as age from person.
Create a Interface that represents your DTO with get-methods to every alias of your native query.
interface MyDTO {
String getFullName();
Integer getAge();
}
The return type of your query now can be this MyDTO
#Query(value = "select name as fullName, age as age from person", nativeQuery=true)
List<MyDTO> findMyDTO();
Is it possible to use JpaRepository without entity?
No, it is not, and it would completely defeat the purpose of JPA, by definition.
JPA is the persistence specification that enables ORM - Object Relational Mapping - that is, you map Java objects to database tables' entries/rows, and Java types to database tables, respectively.
DTO (Data Transfer Object) has nothing to do with ORM, and it serves different purpose (I recommend you to read this article for DTO vs. Entity matter) - transferring data through Java objects - and it usually serves the middle layer, for converting persistent objects(#Entitys) into objects to be used in the web layer (DTOs), and vice versa.
If you really want to avoid persistence layer models (#Entitys), you may go for JDBC abstractions (e.g. Spring Data JDBC), native queries, JPQL, HQL, or a bare JDBC API (which I wouldn't recommend).
but you can try this.
What you can do is you can create your own custom repository class. First, you would have some service class that calls repository class. also notice that we have custom models for the result set of SQL queries.
#Service
public class CustomService {
#Autowired
private CustomRepository repository;
public List<CustomResponse> getAllResult(String id) {
List<Object[]> items = repository.getAllResult(id);
List<CustomResponse> customResponseList = new ArrayList();
for (Object[] item: items) {
CustomResponse c = new CustomResponse();
c.setTestValue1(String.valueOf(item[0]));
c.setTestValue2(String.valueOf(item[1]));
customResponseList.add(c);
}
return customResponseList;
}
}
and your repository class will be look like this.
#Repository
public class CustomRepository {
#Autowired
private EntityManager entityManager;
public List<Object[]> getAllResult(String id) {
Query q = (Query) entityManager.createNativeQuery("SELECT\n" +
" users.user_id as user_id,\n" +
" users.email as user_email\n" +
" FROM Users\n" +
" WHERE users.parent_id = :parent_id;");
q.setParameter("parent_id", id);
List<Object[]> results = q.getResultList();
return results;
}
}
Also you might want to have your own model for that. (like entities)
public class CustomResponse {
private String testValue1;
private String testValue2;
public String getTestValue1() {
return testValue1;
}
public void setTestValue1(String testValue1) {
this.testValue1 = testValue1;
}
public String getTestValue2() {
return testValue2;
}
public void setTestValue2(String testValue2) {
this.testValue2 = testValue2;
}
}
This is possible.
Define base entity and have one column. If you dont want this to exist in database, turn off ddl-auto in application.propeties.
spring.jpa.hibernate.ddl-auto=none
#Entity
#Data
public class BaseEntity {
#Id
private Long id;
}
and use any custom query with any other dao extending jpa repository with BaseEntity.
public interface EmployeeDao extends JpaRepository<BaseEntity, Long> {
#Query(value = "select name from employee where employee_number = ?", nativeQuery = true)
Optional<Employee> get(String employeeNumber);
}
public interface Employee{
String getName();
}

Is it okay to use #MappedSuperclass instead of #Entity to not create a table in the database using JPA?

Explaining the problem, I need to consult a function in POSTGRES:
SELECT * from pgr_dijkstra('SELECT gid AS id, source, target, length AS cost FROM ways', 11111, 22222);
"Pgr_dijkstra" is a function of POSTGIS, not a table. It returns me the shortest path between "source" (11111) and "target (2222)". The result is 6 columns: "seq, path_seq, node, edge, cost and agg_cost".
Because "pgr_dijkstra" is a function, I can't just create a class in my code and annotate it with #Entity, also adding #Id to "seq" and creating the other 5 fields (path_seq, node, edge, cost and agg_cost). This would create a new table in the database. After researching a lot, I found a solution that I believe is far from ideal, which would not be good practice. NOTE: I'm using Spring Boot + Java. The value of "source" and "target" will not be fixed, users will send via browser, I put it fixed just to test this part more quickly.
POJO Class:
public class Dijkstra3 {
public Integer seq;
public Integer path_seq;
public BigInteger node;
public BigInteger edge;
public double cost;
public double agg_cost;
public Dijkstra3(Integer seq, Integer path_seq, BigInteger node, BigInteger edge, double cost, double agg_cost) {
super();
this.seq = seq;
this.path_seq = path_seq;
this.node = node;
this.edge = edge;
this.cost = cost;
this.agg_cost = agg_cost;
}
//GETTERS ...
}
Abstract class with my #SqlResultSetMapping and #NamedNativeQuery. The #SqlResultSetMapping annotation is mapping the result to Dijkstra3.class, which is my POJO. #NamedNativeQuery is my query, which I will use, I point to the "DijkstraMapping" mapping. I annotated the class with #MappedSuperclass, if I didn't do that I would have to annotate with #Entity and a new table in the database would be created.
#SqlResultSetMapping(
name = "DijkstraMapping",
classes = {
#ConstructorResult(
columns = {
#ColumnResult(name="seq", type=Integer.class),
#ColumnResult(name="path_seq", type=Integer.class),
#ColumnResult(name="node", type=BigInteger.class),
#ColumnResult(name="edge", type=BigInteger.class),
#ColumnResult(name="cost", type=Double.class),
#ColumnResult(name="agg_cost", type=Double.class)
},
targetClass = Dijkstra3.class
)
}
)
#NamedNativeQueries({
#NamedNativeQuery(
name = "GetDijkstra",
query = "SELECT * from pgr_dijkstra('SELECT gid AS id, source, target, length AS cost FROM ways', 11111, 22222)",
resultSetMapping = "DijkstraMapping"
)
})
#MappedSuperclass
public abstract class DijkstraSqlMap{
}
Repository
#Repository
public class TestRepository2 {
#PersistenceContext
EntityManager em;
public List<Dijkstra3> callDijkstra(){
TypedQuery<Dijkstra3> query = em.createNamedQuery("GetDijkstra", Dijkstra3.class);
List<Dijkstra3> lista = query.getResultList();
return lista;
}
}
On my Controller or Service:
#Autowired
TestRepository2 testeRepository2;
...
List<Dijkstra3> callHelloWorld = testeRepository2.callDijkstra();
...
It works. After researching and testing everything I found, this was the best way I found to get the result of a query using JPA, pass the data to an object / POJO, and mainly DO NOT CREATE A NEW TABLE IN THE DATABASE, because " pgr_dijkstra "is a function and its return data does not represent a table.
The question is: Is it correct to annotate the DijkstraSqlMap class with #MappedSuperclass so you don't just need to annotate with #Entity? Is there any other better way to get the result of a query in the database and pass it to an object / POJO without creating a new table in the database? I thank you for your time and help.
You can use the Hibernate annotation #Subselect for this purpose and map it as ordinary entity.
#Entity
#Subselect("SELECT * from pgr_dijkstra('SELECT gid AS id, source, target, length AS cost FROM ways', 11111, 22222)")
public class Dijkstra3 {
public Integer seq;
public Integer path_seq;
public BigInteger node;
public BigInteger edge;
public double cost;
public double agg_cost;
}

Filtering data in a table - how to organize it correctly

I study the spring+Hibernate bundle there Is an entity:
public class PersonEntity {
private Long id;
private String name;
private Integer age;
private City city;
private Countrycountry;
...
}
I need to perform filtering. data in this table to display in the browser window. I was thinking of making an implementation in the service of the following methods:
.findByName(name);
.findByNameAndAge(name, age);
.findByNameAndAge(name, age, city);
.findByNameAndAge(name, city);
...
But it turns out that there are too many options for methods. How to make one universal method, i.e. something like a collection in which you can add as many parameters as you need. I started reading on this issue and got completely confused. Somewhere they write about #Filter, somewhere about Hibernate Search, there is also Spring Data Elasticsearch. Tell me the easiest and most relevant way to implement this. If there are links to real examples, I would be very grateful.
Dao:
public interface PersonDao extends GeneralDAO<PersonEntity>{
public List<PersonEntity> searchName(String name);
public List<PersonEntity> searchAllFields(
String name,
Integer age,
City city);
}
GeneralDAO describes all standard methods such as get, save, etc. Repository:
#Repository
public interface PersonRepository extends JpaRepository<PersonEntity, Long> {
List<PersonEntity> findByNameIgnoreCase(String name);
List<PersonEntity> findByNameAndAgeAndCity(
String name,
Integer age,
City city);
}
Service
#Service
#Transactional
public class PersonService implements PersonRepository {
#Autowired
private PersonRepository personRepository;
...
описание всех стандартных методов чтения-записи в БД
#Override
public List<PersonEntity> searchName(String name) {
return productTypeRepository.findByNameIgnoreCase(name);
}
#Override
public List<PersonEntity> searchAllFields(
String name,
Integer age,
City city) {
return personRepository.findByNameAndAgeAndCity(
name,
age,
city);
}
}
In the ad and call controller:
#Autowired
private PersonService personService;
...
personService.searchAllFields(...);
The searchName method works fine, but searchAllFields doesn't. It always returns an empty list, even if I specify one name, the rest = null
I tried to change the method in the service:
List<PersonEntity> findByNameIsNullAndAgeIsNullAndCityIsNull
Spring responds with an error:
"Error creating bean with name personRepository. At least 1 parameter(s) provided but only 0 parameter(s) present in query".
searchAllFields Method is returning an empty list because it contains findByNameAndAgeAndCity which means all the parameters are mandatory and the condition between them is AND so better change to OR (findByNameOrAgeOrCity) so that if you pass single value like name and rest = null then also you will get data and vice-versa.
You should really consider using Criteria API since you are using Spring & Spring Data, you can use JPA Specifications as a complete example see the following example:
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
....
public interface PersonRepository extends JpaRepository<PersonEntity, Long>, JpaSpecificationExecutor {
}
// Notice the the second extended interface JpaSpecificationExecutor ^
in service:
import org.springframework.data.jpa.domain.Specification;
....
public List<PersonEntity> list(PersonEntityFilter personFilter) {
List<PersonEntity> filteredPersons = personsRepository.findAll
(Specification.where(PersonEntitySpecs.findByFilters(personFilter)));
return filteredPersons;
}
PersonEntityFilter is the payload coming from your controller submitted by your clients or your UI and it is a simple class that groups all fields you want to filter by
public class PersonEntityFilter {
private String name;
private Integer age;
private City city;
// getters & setters
}
PersonEntitySpecs is where you put your specs (criteria query logic)
public class PersonEntitySpecs {
public static Specification<PersonEntity> findByFilters(PersonEntityFilter personEntityFilter) {
return (root, query, cb) -> {
final Collection<Predicate> predicates = new ArrayList<>();
if (personEntityFilter.getName() != null) {
predicates.add(cb.like(root.get("name"), "%" + personEntityFilter.getName() + "%")));
}
if (personEntityFilter.getAge() != null) {
predicates.add(cb.equal(root.get("age"), personEntityFilter.getAge()));
}
if (personEntityFilter.getCity() != null) {
Join<PersonEntity, CityEntity> personCityJoin = root.join("city");
predicates.add(cb.equal(personCityJoin.get("id"), personEntityFilter.getCity().getId()));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
}

Spring JPA - "java.lang.IllegalArgumentException: Projection type must be an interface!" (using native query)

I'm trying to retrieve a timestamp date from an oracle database but the code is throwing:
java.lang.IllegalArgumentException: Projection type must be an
interface!
I'm trying to use native query because the original query is way to complex to use Spring JPA methods or JPQL.
My code is similar to this one below (Sorry, can't paste the original one due to company policy).
Entity:
#Getter
#Setter
#Entity(name = "USER")
public class User {
#Column(name = "USER_ID")
private Long userId;
#Column(name = "USER_NAME")
private String userName;
#Column(name = "CREATED_DATE")
private ZonedDateTime createdDate;
}
Projection:
public interface UserProjection {
String getUserName();
ZonedDateTime getCreatedDate();
}
Repository:
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
#Query(
value = " select userName as userName," +
" createdDate as createdDate" +
" from user as u " +
" where u.userName = :name",
nativeQuery = true
)
Optional<UserProjection> findUserByName(#Param("name") String name);
}
I'm using Spring Boot 2.1.3 and Hibernate 5.3.7.
I had this same issue with a very similar projection:
public interface RunSummary {
String getName();
ZonedDateTime getDate();
Long getVolume();
}
I do not know why, but the issue is with ZonedDateTime. I switched the type of getDate() to java.util.Date, and the exception went away. Outside of the transaction, I transformed the Date back to ZonedDateTime and my downstream code was not affected.
I have no idea why this is an issue; if I don't use projection, the ZonedDateTime works out-of-the-box. I'm posting this as an answer in the meantime because it should be able to serve as a workaround.
According to this bug on the Spring-Data-Commons project, this was a regression caused by adding support for optional fields in the projection. (Clearly it's not actually caused by that other fix -- since that other fix was added in 2020 and this question/answer long predates it.) Regardless, it has been marked as resolved in Spring-Boot 2.4.3.
Basically, you couldn't use any of the Java 8 time classes in your projection, only the older Date-based classes. The workaround I posted above will get around the issue in Spring-Boot versions before 2.4.3.
When you call method from projection interface spring takes the value it received from the database and converts it to the type that method returns. This is done with the following code:
if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(rawType)) { //if1
return projectCollectionElements(asCollection(result), type);
} else if (type.isMap()) { //if2
return projectMapValues((Map<?, ?>) result, type);
} else if (conversionRequiredAndPossible(result, rawType)) { //if3
return conversionService.convert(result, rawType);
} else { //else
return getProjection(result, rawType);
}
In the case of getCreatedDate method you want to get java.time.ZonedDateTime from java.sql.Timestamp. And since ZonedDateTime is not a collection or an array (if1), not a map (if2) and spring does not have a registered converter (if3) from Timestamp to ZonedDateTime, it assumes that this field is another nested projection (else), then this is not the case and you get an exception.
There are two solutions:
Return Timestamp and then manually convert to ZonedDateTime
Create and register converter
public class TimestampToZonedDateTimeConverter implements Converter<Timestamp, ZonedDateTime> {
#Override
public ZonedDateTime convert(Timestamp timestamp) {
return ZonedDateTime.now(); //write your algorithm
}
}
#Configuration
public class ConverterConfig {
#EventListener(ApplicationReadyEvent.class)
public void config() {
DefaultConversionService conversionService = (DefaultConversionService) DefaultConversionService.getSharedInstance();
conversionService.addConverter(new TimestampToZonedDateTimeConverter());
}
}
Spring Boot 2.4.0 update:
Since version 2.4.0 spring creates a new DefaultConversionService object instead of getting it via getSharedInstance and I don't know proper way to get it other than using reflection:
#Configuration
public class ConverterConfig implements WebMvcConfigurer {
#PostConstruct
public void config() throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException {
Class<?> aClass = Class.forName("org.springframework.data.projection.ProxyProjectionFactory");
Field field = aClass.getDeclaredField("CONVERSION_SERVICE");
field.setAccessible(true);
GenericConversionService service = (GenericConversionService) field.get(null);
service.addConverter(new TimestampToZonedDateTimeConverter());
}
}
A new attribute converter can be created to map column type to desired attribute type.
#Component
public class OffsetDateTimeTypeConverter implements
AttributeConverter<OffsetDateTime, Timestamp> {
#Override
public Timestamp convertToDatabaseColumn(OffsetDateTime attribute) {
//your implementation
}
#Override
public OffsetDateTime convertToEntityAttribute(Timestamp dbData) {
return dbData == null ? null : dbData.toInstant().atOffset(ZoneOffset.UTC);
}
}
In the projection, it can be used like below. This is an explicit way of calling the converter. I couldn't find how to register it automatically so that you don't need to add #Value annotation every time you need.
#Value("#{#offsetDateTimeTypeConverter.convertToEntityAttribute(target.yourattributename)}")
OffsetDateTime getYourAttributeName();
I had the same issue with Spring Boot v2.4.2
I wrote this ugly hack that fixed it for me:
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.convert.Jsr310Converters;
import org.springframework.data.util.NullableWrapperConverters;
#Configuration
public class JpaConvertersConfig {
#EventListener(ApplicationReadyEvent.class)
public void config() throws Exception {
Class<?> aClass = Class.forName("org.springframework.data.projection.ProxyProjectionFactory");
Field field = aClass.getDeclaredField("CONVERSION_SERVICE");
field.setAccessible(true);
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
DefaultConversionService sharedInstance = ((DefaultConversionService) DefaultConversionService.getSharedInstance());
field.set(null, sharedInstance);
Jsr310Converters.getConvertersToRegister().forEach(sharedInstance::addConverter);
NullableWrapperConverters.registerConvertersIn(sharedInstance);
}
}
You have declared userId field as Long in the entity but in UserProjection getUserId method return type is String. which is mismatching so Change
String getUserId();
to
Long getUserId();
I never got interface to work and not sure if it is supported with ZonedDateTime though no reason for not supporting occurs in my mind.
For that I created a class that I use with projection (of course this could implement that interface but for the sake of simplicity I left it out).
#Getter
#Setter
#AllArgsConstructor
public class UserProjection {
private String userName;
private ZonedDateTime createdDate;
}
This requires JPQL because using NEW operator in the query, so like:
#Query(value = " SELECT NEW org.example.UserProjection(U.userName, U.createdDate) "
+ " FROM USER U " // note that the entity name is "USER" in CAPS
+ " WHERE U.userName = :name ")
The problem that is spring data jpa cannot convert some types from database into java types.
I had almost the same issue when tried to get boolean as result and database returns number.
Look at more at:
https://github.com/spring-projects/spring-data-commons/issues/2223
https://github.com/spring-projects/spring-data-commons/issues/2290

JPA enum query ERROR on playframework

I am working on project using java playframework 1.2.4 and I have a #Entity class. It is look like
#Entity
public class EmployeeType extends Model {
public static enum TYPE { HOURLY, DAILY, MONTHLY };
public static enum NATIONALITY { LOCAL, FOREIGN };
#Required
#Enumerated(EnumType.STRING)
public TYPE type;
#Required
#Enumerated(EnumType.STRING)
public NATIONALITY nationality;
}
And in my controller class I want to get list of EmployeeTypes using my 2 enum attributes.
Query looks like
Query query = JPA.em().createQuery("SELECT e FROM EmployeeType e where " +
"e.nationality = :nationality " +
"and e.type = :type");
query.setParameter("nationality", NATIONALITY.LOCAL);
query.setParameter("type", TYPE.HOURLY);
List<models.EmployeeType> employeeType = query.getResultList()
Gives this error: IllegalArgumentException occured : Parameter value [LOCAL] was not matching type [models.EmployeeType$NATIONALITY]
What should i do?
The error is possibly because of the fact that your enums are nested in your entity. You need to access it on entity name.
You can change your setParameter code to: -
query.setParameter("nationality", EmployeeType.NATIONALITY.LOCAL);
query.setParameter("type", EmployeeType.TYPE.HOURLY);

Categories

Resources