Hi,
I am trying to create dynamic SQL query that supports paginations, like the one provided by JpaRepository - Page findAll(Specification spec, Pageable pageable).
The UI is on React, so only the Backend is on JMIX.
I am trying to create a filter that returns pageable result and total number of pages/elements:
This is the table:
@DbView
@JmixEntity
@Entity
@Table(name = "MY_TABLE")
public class MyTable {
@Id
@Column(name = "ID", nullable = false)
private Long id;
@Column(name = "TYPE_ID", nullable = false)
private Long typeId;
@Column(name = "TYPE_NAME", length = 1000)
private String typeName;
//---
}
I need to filter for typeId and typeName(and 10 other fields). The input parameters for the query are lists of strings. Both lists can be null.
With DataManager I have Pagination, BUT I do NOT have the total number of pages/elements:
//---
@Autowired
private final DataManager dataManager;
public Page<MyTable> getResult(List<String> typeIds, List<String> typeNames, int page, int size) {
LogicalCondition logicalCondition = LogicalCondition.and();
// -----
if (CollectionUtils.isNotEmpty(typeIds)) {
logicalCondition = logicalCondition.add(PropertyCondition.inList("typeId", typeIds));
}
if (CollectionUtils.isNotEmpty(typeNames)) {
logicalCondition = logicalCondition.add(PropertyCondition.inList("typeName", typeNames));
}
List<MyTable> result = dataManager
.load(MyTable.class).condition(logicalCondition)
.firstResult((page - 1) * size)
.maxResults(size)
.sort(Sort.by(Sort.Direction.DESC, "id"))
.list();
// ----
}
So in order to get the number of pages I need to create a second query,
Integer count = dataManager
.loadValue("SELECT count(t.id) FROM MY_TABLE t WHERE ...."), Integer.class)
.setParameters(parameters)
.one();
The loadValue method of DataManager does not support condition, so I need to write the second query manually. And I do not want to have to 2 different queries for the pretty much same request - the only difference between the requests will be the paging and sorting.
I can build the query manually and use it for both requests, but it looks really bad.
List<String> myConditions = new ArrayList<>();
Map<String, Object> parameters = new HashMap<>();
if (CollectionUtils.isNotEmpty(typeIds)) {
myConditions.add("t.typeId IN :typeIds");
parameters.put("typeIds", typeIds);
}
//......
Doing this for 10+ parameters is not good. And I want to get the data with a single request.
I tried using the JmixRepository like:
@Repository
public interface MyRepository extends JmixDataRepository<MyTable, Long> {
@Query("SELECT t FROM MyTable t WHERE " +
"(:typeIds IS NULL OR t.typeId IN :typeIds) " +
"AND (:personNames IS NULL OR t.personName IN :personNames) ")
Page<MyTable> findMeSomething(
@Param(value = "typeIds") List<Long> typeIds,
@Param(value = "personNames") List<String> personNames,
Pageable pageable);
}
But it does NOT work because IS NULL can not be used on objects and lists are objects. If the input parameters are primitive types it works as expected, but in my case I got lists, dates etc.
There must be a better way to do this.
Any ideas ?
Thanks,
Yordan