Select a unique names from Users that have more than 3 Articles. Spring Data, H2 - spring-boot

I use: Spring Boot, Spring Data, and H2 (in-memory) DataBase.
DB TABLES:
CREATE TABLE user
(
id INT AUTO_INCREMENT,
name VARCHAR(250) NOT NULL,
age INT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE article
(
id INT AUTO_INCREMENT,
text TEXT NOT NULL,
color ENUM ('red', 'green', 'blue', 'yellow', 'pink') NOT NULL,
user_id INT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE ON UPDATE CASCADE
);
In ArticleRepository exploited such query:
SELECT u.name, a.user_id, count() FROM user AS u INNER JOIN article AS a ON u.id = a.user_id GROUP BY a.user_id HAVING COUNT() > 3;
#Repository
public interface ArticleRepository extends JpaRepository<Article, Integer> {
#Query(value = "SELECT u.name, a.user_id, count(*) FROM user AS u INNER JOIN article AS a ON u.id = a.user_id GROUP BY a.user_id HAVING COUNT(*) > 3", nativeQuery = true)
List<Article> findUserNamesByArticlesCountMoreThan();
}
After request I receive the error:
In Postman:
"error": "Internal Server Error", "message": "could not execute query;
SQL [SELECT u.name, a.user_id, count(text) FROM user AS u INNER JOIN
article AS a ON u.id = a.user_id GROUP BY a.user_id HAVING COUNT(*) >
3]; nested exception is org.hibernate.exception.SQLGrammarException:
could not execute query",
In IntelliJ Idea:
02:54:24.681 [http-nio-9090-exec-1] WARN SqlExceptionHelper - SQL
Error: 42122, SQLState: 42S22 02:54:24.681 [http-nio-9090-exec-1]
ERROR SqlExceptionHelper - Column "id" not found [42122-197]
02:54:24.703 [http-nio-9090-exec-1] ERROR [dispatcherServlet] -
Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception [Request processing failed; nested exception is
org.springframework.dao.InvalidDataAccessResourceUsageException: could
not execute query; SQL [SELECT u.name, a.user_id, count(text) FROM
user AS u INNER JOIN article AS a ON u.id = a.user_id GROUP BY
a.user_id HAVING COUNT(*) > 3]; nested exception is
org.hibernate.exception.SQLGrammarException: could not execute query]
with root cause org.h2.jdbc.JdbcSQLException: Column "id" not found
[42122-197] at
org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179) at
org.h2.message.DbException.get(DbException.java:155) at
org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3148) at
org.h2.jdbc.JdbcResultSet.get(JdbcResultSet.java:3247) at
org.h2.jdbc.JdbcResultSet.getInt(JdbcResultSet.java:346)..............
Help me to resolve this problem, and find a mistake.
Entities:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "article")
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#Column(name = "text", nullable = false)
private String text;
#Column(name = "color", nullable = false, unique = true)
#Enumerated(EnumType.STRING)
private Color color;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
#JoinColumn(name = "user_id", referencedColumnName="id")
private User user;
}
.
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString(exclude = "articles")
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Integer id;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "age", nullable = false)
private Integer age;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<Article> articles;
}
Service:
#Service
public class ArticleService {
private ArticleRepository articleRepository;
#Autowired
public ArticleService(ArticleRepository articleRepository) {
this.articleRepository = articleRepository;
}
public List<Article> findAllUserNamesByArticlesMoreThan() {
return articleRepository.findUserNamesByArticlesCountMoreThan(); }}
ArticleDtoService:
#Service
public class ArticleDtoService {
private ArticleService articleService;
#Autowired
public ArticleDtoService(ArticleService articleService) {
this.articleService = articleService;
}
public ResponseEntity<List<ArticleDto>> getAllUserNamesByArticlesMoreThan() {
List<Article> articles = articleService.findAllUserNamesByArticlesMoreThan();
Link link = linkTo(methodOn(ArticleController.class).getAllUserNamesListByArticlesMoreThan()).withSelfRel();
return new ResponseEntity<>(createArticleDtoList(articles, link), HttpStatus.OK); }}
ArticleController:
#RestController
public class ArticleController {
private final ArticleDtoService articleDtoService;
#Autowired
public ArticleController(ArticleDtoService articleDtoService) {
this.articleDtoService = articleDtoService;
}
#GetMapping(value = "/api/articles/count")
public ResponseEntity<List<ArticleDto>> getAllUserNamesListByArticlesMoreThan() {
return articleDtoService.getAllUserNamesByArticlesMoreThan(); }}
ArticleDto:
public class ArticleDto extends ResourceSupport {
public Article article;
public ArticleDto(Article article, Link selfLink) {
this.article = article;
add(selfLink); }}

Related

Using JpaSpecificationExecutor with EntityGraph

I am using a implementation of JpaSpecificationExecutor and trying to use in the repository the #EntityGraph for select which relationships entity they get in a complex query.
My entities examples (all relationships bidireccional)
#Entity
#Table(name = "trazabilidad_contenedor")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class TrazabilidadContenedor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "traConSeq")
#SequenceGenerator(name = "traConSeq")
private Long id;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "trazabilidadContenedors", allowSetters = true)
private PromoProGesCodLer promoProGesCodeLer;
.
.
.
#Entity
#Table( name = "promo_pro_ges_cod_ler")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class PromoProGesCodLer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "promoProGesCodLers", allowSetters = true)
private ProGesCodLer procesoGestoraCodLer;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "promoProGesCodLers", allowSetters = true)
private Promocion promocion;
.
.
.
#Entity
#Table(name = "promocion")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Promocion implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
.
.
.
#Entity
#Table(name = "pro_ges_cod_ler")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
#NextProGesCodLer
public class ProGesCodLer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pgclSeq")
#SequenceGenerator(name = "pgclSeq")
private Long id;
#OneToMany(mappedBy = "procesoGestoraCodLer")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<PromoProGesCodLer> promoProGesCodLers = new HashSet<>();
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "proGesCodLers", allowSetters = true)
private ProcesoGestora procesoGestora;
.
.
.
And this is my repository
#Repository
public interface TrazabilidadContenedorRepository
extends JpaRepository<TrazabilidadContenedor, Long>, JpaSpecificationExecutor<TrazabilidadContenedor> {
#EntityGraph (
type = EntityGraph.EntityGraphType.FETCH,
attributePaths = {
"promoProGesCodeLer",
"promoProGesCodeLer.promocion",
"promoProGesCodeLer.promocion.direccion",
"promoProGesCodeLer.promocion.direccion.municipio",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.codLER",
"promoProGesCodeLer.procesoGestoraCodLer.codLER.lerType",
"promoProGesCodeLer.procesoGestoraCodLer.nextProGesCodLer",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora",
}
)
List<TrazabilidadContenedor> findAll(Specification<TrazabilidadContenedor> var1);
}
The constructor of my Specification‹TrazabilidadContenedor›
protected Specification<TrazabilidadContenedor> createSpecification(TrazabilidadContenedorCriteria criteria) {
Specification<TrazabilidadContenedor> specification = Specification.where(null);
if (criteria != null) {
if (criteria.getPromocionId() != null) {
specification =
specification.and((root, query, builder) ->
builder.equal(
root
.join(TrazabilidadContenedor_.promoProGesCodeLer, JoinType.LEFT)
.join(PromoProGesCodLer_.promocion, JoinType.LEFT)
.get(Promocion_.id),
criteria.getPromocionId()
)
);
}
if (criteria.getGestoraId() != null) {
specification =
specification.and(
(root, query, builder) ->
builder.equal(
root
.join(TrazabilidadContenedor_.promoProGesCodeLer, JoinType.LEFT)
.join(PromoProGesCodLer_.procesoGestoraCodLer, JoinType.LEFT)
.join(ProGesCodLer_.procesoGestora, JoinType.LEFT)
.join(ProcesoGestora_.gestora, JoinType.LEFT)
.get(Gestora_.id),
criteria.getGestoraId()
)
);
}
}
return specification;
}
When i have only one criteria , criteria.getPromocionId() or criteria.getGestoraId() it's OK , but if i use both at the same time i obtain.
Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias2,role=com.cocircular.greenadvisor.domain.PromoProGesCodLer.promocion,tableName=promocion,tableAlias=promocion2_,origin=promo_pro_ges_cod_ler promoproge1_,columns={promoproge1_.promocion_id,className=com.cocircular.greenadvisor.domain.Promocion}}] [select generatedAlias0 from com.cocircular.greenadvisor.domain.TrazabilidadContenedor as generatedAlias0 inner join generatedAlias0.promoProGesCodeLer as generatedAlias1 inner join generatedAlias1.promocion as generatedAlias2 inner join generatedAlias0.promoProGesCodeLer as generatedAlias3 inner join generatedAlias3.procesoGestoraCodLer as generatedAlias4 inner join generatedAlias4.procesoGestora as generatedAlias5 inner join generatedAlias5.gestora as generatedAlias6 where ( generatedAlias0.traceabilityStatus=:param0 ) and ( ( generatedAlias6.id=75304L ) and ( generatedAlias2.id=86754L ) )]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1542)
at org.hibernate.query.Query.getResultList(Query.java:165)
at org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:76)
For this i'm usign Hibernate 5.4.15 and Spring-Boot 2.2.7.RELEASE.
Every item, presented in generated sql is bound to be present in graph.
So, let's write a full graph path:
select generatedAlias0
from com.cocircular.greenadvisor.domain.TrazabilidadContenedor as generatedAlias0
inner join generatedAlias0.promoProGesCodeLer as generatedAlias1 ---> promoProGesCodeLer
inner join generatedAlias1.promocion as generatedAlias2 ---> promoProGesCodeLer.promocion
inner join generatedAlias0.promoProGesCodeLer as generatedAlias3 ---> promoProGesCodeLer
inner join generatedAlias3.procesoGestoraCodLer as generatedAlias4 ---> promoProGesCodeLer.procesoGestoraCodLer
inner join generatedAlias4.procesoGestora as generatedAlias5 ---> promoProGesCodeLer.procesoGestoraCodLer.procesoGestora
inner join generatedAlias5.gestora as generatedAlias6 ----> promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora
where ( generatedAlias0.traceabilityStatus=:param0 )
and ( ( generatedAlias6.id=75304L ) and ( generatedAlias2.id=86754L ) )
Here's the provided graph:
attributePaths = {
"promoProGesCodeLer",
"promoProGesCodeLer.promocion",
"promoProGesCodeLer.promocion.direccion",
"promoProGesCodeLer.promocion.direccion.municipio",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.codLER",
"promoProGesCodeLer.procesoGestoraCodLer.codLER.lerType",
"promoProGesCodeLer.procesoGestoraCodLer.nextProGesCodLer",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora" }
Looks to me, that node promoProGesCodeLer.procesoGestoraCodLer is missing from graph

#GeneratedValue annotation is not working on mapping table

I have a many to many relationship like below.
#Entity
#Table(name = "employees")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "EMP_ID")
private int id;
private String firstName;
private String lastName;
#JoinTable(name = "employee_project_mapping", joinColumns = #JoinColumn(name = "EMPLOYEE_ID", referencedColumnName = "EMP_ID"), inverseJoinColumns = #JoinColumn(name = "PROJECT_ID", referencedColumnName = "PJT_ID"))
#JsonManagedReference
#ManyToMany(cascade = CascadeType.ALL)
Set<Project> projects = new HashSet<Project>();
.....
.....
}
#Entity
#Table(name = "projects")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PJT_ID")
private int projectId;
private String projectName;
private int teamSize;
#ManyToMany(mappedBy = "projects")
#JsonBackReference
private Set<Employee> emps = new HashSet<Employee>();
.....
.....
}
#Entity
#Table(name = "employee_project_mapping")
public class EmployeeProjectMapping {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "EMP_PJT_ID")
private Integer empPjtId;
#Column(name = "PROJECT_ID")
private Integer projectId;
#Column(name = "EMPLOYEE_ID")
private Integer emploeeId;
.....
.....
}
But when I am trying to insert an employee object with set of projects, it is failing to create auto generated id for the column EMP_PJT_ID (this is an id to the mapping table record). Can't I add an auto generated id for mapping table using jpa?
Error trace
Hibernate: insert into employees (emp_id, first_name, last_name) values (null, ?, ?)
Hibernate: insert into employee_project_mapping (employee_id, project_id) values (?, ?)
2021-04-22 23:34:25.973 ERROR 24126 --- [nio-8080-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : NULL not allowed for column "EMP_PJT_ID"; SQL statement:
insert into employee_project_mapping (employee_id, project_id) values (?, ?) [23502-200]
2021-04-22 23:34:25.975 ERROR 24126 --- [nio-8080-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "EMP_PJT_ID"; SQL statement:
insert into employee_project_mapping (employee_id, project_id) values (?, ?) [23502-200]
The mapping of a many-to-many should be:
#Entity
#Table(name = "employees")
public class Employee {
...
#OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, orphanRemoval = true)
Set<EmployeeProjectMapping> projects = new HashSet<EmployeeProjectMapping>();
...
// Utility method to update both sides of the association
public void addProject(Project project) {
EmployeeProjectMapping empProject = new PersEmployeeProjectMappingonAddress( this, project );
projects.add( empProject );
project.getEmployees().add( empProject );
}
}
#Entity
#Table(name = "projects")
public class Project {
...
#OneToMany(mappedBy = "project", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<EmployeeProjectMapping> emps = new HashSet<Employee>();
...
}
#Entity
#Table(name = "employee_project_mapping")
public class EmployeeProjectMapping {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "EMP_PJT_ID")
private Integer empPjtId;
#Id
#ManyToOne
#JoinColumn(name = "PROJECT_ID")
private Project project;
#Id
#ManyToOne
#JoinColumn(name = "EMPLOYEE_ID")
private Employee employee;
.....
.....
}
Make sure to check the example on the Hibernate ORM documentation for all the details.

Inner join in spring boot data jpa

I am using spring boot data jpa 1.4 and I'm fairly new to it.
My table definition is here. Its fairly simple, there are 2 tables (Groups and Users).
The group table contains group_id(primary key), group_name, group_active(values=Y/N).
The group table can ideally have only one row which is has group_active to 'Y', the rest should have 'N'
The user table contains user_id(primary key), user_name, group_id(foreign key from group).
Following are my entity classes
Group:
#Entity
#Table(schema = "HR", name = "GROUPS")
public class Group {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "GROUP_ID")
private Long id;
#Column(name = "GROUP_NAME")
private String name;
#Column(name = "GROUP_ACTIVE")
private String active;
User:
#Entity
#Table(schema = "HR", name = "USERS")
public class User {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "USER_ID")
private Long id;
#Column(name = "USER_NAME")
private String name;
#Column(name = "GROUP_ID")
private Long groupId;
#ManyToMany
#JoinTable(
schema = "HR",
name = "GROUPS",
joinColumns = {#JoinColumn(table = "GROUPS", name = "GROUP_ID", insertable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(table = "USERS", name = "GROUP_ID", insertable = false, updatable = false)}
)
#WhereJoinTable(clause = "GROUP_ACTIVE='Y'")
private List<Group> group;
Repository class:
public interface UserRepository extends CrudRepository<User, Long>{
List<User> findByName (String name);
}
Query: This is the query I want to execute, which is a simple inner join.
SELECT U.*
FROM HR.USER U, HR.GROUP G
WHERE U.GROUP_ID=G.GROUP_ID
AND G.GROUP_ACTIVE='Y'
AND U.USER_NAME=?
What would be the correct way to write the #JoinTable or #JoinColumn such that I always get back one user that belongs to the active group with the name ?
I have done some tests based on your set-up and the solution would need to use filters (assuming there is only one Group with Group_Activity = 'Y'):
Group Entity
#Entity
#Table(schema = "HR", name = "GROUPS")
public class Group {
#OneToMany(mappedBy = "group")
#Filter(name = "activityFilter")
private Set<User> users;
User Entity
#Entity
#Table(schema = "HR", name = "USERS")
#FilterDef(name="activityFilter"
, defaultCondition="group_id =
(select g.id from groups g where g.GROUP_ACTIVE='Y')")
public class User {
#ManyToOne
#JoinColumn(name = "group_id")
private Group group;
When making a query
session.enableFilter("activityFilter");
session.createQuery("select u from Group g inner join g.users u where u.user_name = :userName");
Additionally if there are many groups with activity = 'Y' then try this:
#FilterDef(name="activityFilter"
, defaultCondition="group_id in
(select g.id from group g where g.GROUP_ACTIVE='Y')")

HQL query for Association

I am having below tables here but having some problem while fetching results.
#Entity
#Table(name = "USER_VW")
public class WorkspaceUserImpl
{
#JoinColumn(name = "USER_ID", insertable=false, updatable=false)
#OneToOne(targetEntity = UserImpl.class, fetch = FetchType.EAGER)
private User user;
}
#Table(name = "IK_USER")
#Inheritance(strategy = InheritanceType.JOINED)
#AttributeOverride(name = "id", column = #Column(name = "USER_ID") )
public class UserImpl extends BaseAuditable<UserIdentifier>implements User, UserAuthentication {
private static Logger log = LoggerFactory.getLogger(UserImpl.class);
#Id
#Type(type = "com.commons.UserIdentifierTypeMapper")
#Column(name = "USER_ID")
private UserIdentifier id;
}
and User
Public Inteface User
{
UserIdentifier getId();
}
Now i have written an HQL query to fetch all the data from WorkspaceUserImpl class with a given user ID for UserImpl class like below.
SELECT w from WorkspaceUserImpl w where w.user.id = : user_id;
and also tried
SELECT w from WorkspaceUserImpl as w INNER JOIN w.user as u where u.id = : user_id;
and even tried with JOIN FETCH also
and setting the parameter user_id with some say 1234.
but am getting List as emply for the partcular ID but in DB its having 5 records.
am i making any query mistake here? kindly advice..
Have you tried below query:
from WorkspaceUserImpl as w JOIN FETCH w.user as u where u.id = : user_id;

QueryDSL - HHH000104: firstResult/maxResults specified with collection fetch; applying in memory

In my Spring Boot/Data/JPA/QueryDSL application I have a following entities:
#Entity
#NamedEntityGraph(name = "graph.User", attributeNodes = { #NamedAttributeNode("authorities") })
#Table(name = "users")
public class User extends BaseEntity implements UserDetails {
private static final long serialVersionUID = 8884184875433252086L;
#Id
#SequenceGenerator(name = "users_id_seq", sequenceName = "users_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "users_id_seq")
private Long id;
private String username;
....
#JsonIgnore
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "users_authorities", joinColumns = { #JoinColumn(name = "user_id") }, inverseJoinColumns = { #JoinColumn(name = "authority_id") })
private Set<Authority> authorities = new HashSet<Authority>();
....
}
#Entity
#Table(name = "authorities")
public class Authority implements GrantedAuthority {
private static final long serialVersionUID = 6118293571787931020L;
#Id
#SequenceGenerator(name = "authorities_id_seq", sequenceName = "authorities_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "authorities_id_seq")
private Integer id;
#NotEmpty
private String name;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "authorities")
private Set<User> users = new HashSet<User>();
....
}
and a following load method:
#Override
public List<User> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
PageRequest pageRequest = null;
Page<User> page;
int pageIndex = first / pageSize;
if (sortField == null || sortField.isEmpty()) {
pageRequest = new PageRequest(pageIndex, pageSize);
} else {
Sort.Direction direction = sortOrder == SortOrder.ASCENDING ? Sort.Direction.ASC : Sort.Direction.DESC;
pageRequest = new PageRequest(pageIndex, pageSize, new Sort(direction, sortField));
}
Predicate predicate = UserExpressions.lazyPredicate(filters);
page = userService.findAll(predicate, pageRequest);
....
}
After this method invocation I see following debug information:
Hibernate: select count(user0_.id) as col_0_0_ from users user0_ where user0_.id is not null
1266079 WARN o.h.h.i.ast.QueryTranslatorImpl - HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!
Hibernate: select user0_.id as id1_10_0_, authority2_.id as id1_0_1_, user0_.created_date as created_2_10_0_, user0_.updated_date as updated_3_10_0_, user0_.account_non_locked as account_4_10_0_, user0_.age as age5_10_0_, user0_.birthday as birthday6_10_0_, user0_.email as email7_10_0_, user0_.enabled as enabled8_10_0_, user0_.first_name as first_na9_10_0_, user0_.gender as gender10_10_0_, user0_.last_name as last_na11_10_0_, user0_.password as passwor12_10_0_, user0_.username as usernam13_10_0_, authority2_.name as name2_0_1_, authoritie1_.user_id as user_id1_10_0__, authoritie1_.authority_id as authorit2_11_0__ from users user0_ left outer join users_authorities authoritie1_ on user0_.id=authoritie1_.user_id left outer join authorities authority2_ on authoritie1_.authority_id=authority2_.id where user0_.id is not null
As you can see, according to "WARN o.h.h.i.ast.QueryTranslatorImpl - HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!" - pagination is applied in memory that is not completely acceptable in case of thousands records.
How to change my configuration in order to apply pagination at database level ?

Resources