Pagination in Spring using #RestController, but without using Spring Data Rest Pageable? - spring

I know using Spring Data Rest I can use the in-built functionality of Pagination Like this
Page<Product> findByCategoryId(#RequestParam("id") Long id, Pageable pageable);
However, I am in project I am using Spring mvc #RestController and want to achive the same functionality
I tried like this:-
Session currentSession = entityManager.unwrap(Session.class);
Query<Product> theQuery = currentSession.createQuery("from Product", Product.class);
theQuery.setFirstResult((pageNumber-1) * pageSize); // This is 0 based
theQuery.setMaxResults(pageSize);
List<Product> dataList = theQuery.getResultList();
return dataList;
It works but I don't get the count of total number of records in the table.
And for UI pagination I need that.
So do I have to hit 2 queries everytime first like above then 1 query to fetch record size. (Which can cause data sync problems if records are updated)
Or
Is there a better way to achieve this in SINGLE QUERY

If you need the total number of records then you must create a second query.
You could do that in one query with a subquery but then you cannot use Entities as return type.
Regarding data sync problems: If you run both queries in the same transaction there is no problem.
Btw. why do you unwrap the Hiberante Session? There is no need for that in your example.

Related

Force JPA to not use union and fetch tables one by one

I have 5 similar tables from which I need to execute a same query and fetch data in pages. I have used polymorphic queries (have super abstract class and used #Inheritance to fetch all rows automatically)
But this approach has problems as noted here: Database pressure on Polymorphic queries
The issue is that the queries use union all which makes DB to search through millions of rows just to get 500 results. So instead I want to execute this serially.
When I execute the method JPA will go to first table; fetch data in pages; if the data fetching is complete then go to second table and so on...
Right now with union, I have ton of pressure on database. With this new approach, I could have less pressure as only one table is accessed at once.
I do not know a way to do this without changing the setup I have right now. For example right now I have it like this:
public interface OhlcDao extends JpaRepository<AbstractOhlc, OhlcId> {
Slice<OhlcRawBean<? extends OhlcBean>> findByIdSourceIdAndIdTickerIdIn(
String sourceId,
Set<String> tickerId,
PageRequest pageRequest
);
}
The method uses union to fetch data which I do not like.
Is there a way to make this work in JPA or Hibernate by changing any internal code (aka without changing my setup, so similar method does not use unions)

Executing an SQL query in multiple databases through Spring - Hibernate

I have a below problem and I am looking for solution in Spring - MVC and Hibernate only.
Problem Statement: There is UI which is having a text area and Submit button. In text area user can write a SQL query and after submitting, this SQL query has to be executed at multiple databases.
Note: Assume that multiple databases are already configured.
Please tell me the best approach for implementing it.
You might consider 2 options:
AbstractRoutingDataSource
With this solution you are able to switch to the right database before executing queries. So you could write something like
// GOLD database
CustomerContextHolder.setCustomerType(CustomerType.GOLD);
List<Item> goldItems = catalog.getItems();
assertEquals(3, goldItems.size());
System.out.println("gold items: " + goldItems);
// SILVER database
CustomerContextHolder.setCustomerType(CustomerType.SILVER);
List<Item> silverItems = catalog.getItems();
assertEquals(2, silverItems.size());
System.out.println("silver items: " + silverItems);
// DEFAULT database
CustomerContextHolder.clearCustomerType();
List<Item> bronzeItems = catalog.getItems();
assertEquals(1, bronzeItems.size());
System.out.println("bronze items: " + bronzeItems);
Here are some docs:
https://spring.io/blog/2007/01/23/dynamic-datasource-routing/
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.html
http://fedulov.website/2015/10/14/dynamic-datasource-routing-with-spring/
Using multiple transaction manager (one by database)
This involve that you know in advance what Transaction Manager you will need for a specific Service.
https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-multiple-tx-mgrs-with-attransactional
I will assume that you have multiple datasources wired in you application context (?). If so and assuming that they have different qualifiers, you can inject them into another component, typically a service which is invoked from your controller or directly into your controller.
#Autowired
List<DataSource> datasources;
Should do the trick, alternatively through constructor injection. With the latter, you can create a JdbcTemplate per DataSource. Then you loop through the list and execute the same sql query on all datasources.

How to limit the results of a Spring Repository with custom query

I am using a Spring repository to query a database, but because of the nature of my application I need to use a custom #Query in order to JOIN FETCH lazy collections.
This process works fine, but now I need to limit the result to a single record. I understand that Spring has the notion of findFirst or findTop1 in the method names, but this does not appear to work when you have a custom query.
How can I use a custom query and limit the result to 1 record when using a Spring repository?
you need to pass a Pageable param in your query method
#Query("select e from Entity e LEFT JOIN FETCH e.list")
public Page<Entity> find(Pageable pageable);
and call the method passing the object
repository.find(new PageRequest(0, 1));

jpa pagination suppress count query

We are using Spring Data JPA Repository.
For pagination we are passing the Pageable object to the JPA Repository findBy Methods.
Since in our UI , we are not displaying the total count of records, we don't want the count query to be fired .
Is there any way to suppress the count query fired during pagination ?
Have your repository method return List<Entity> rather than Page<Entity>, and I believe it won't run the count query.
See "Special Parameter Handling" in Spring Data JPA documentation section "1.2.2 Defining query methods".

Projection on a MongoDb Query using Spring data and QueryDSL

I have a Spring MVC/Spring Data / Mongo DB application.
I have setted up my environement according the the spring data documentation and my repositories work fine (I can execute queries with predicates)
I was wondering if it was possible to execute a type safe query (using Spring Data and QueryDSL) while making a projection (I want only a few fields of a very big document).
The QueryDSL documentation gives an example for Hibernate but states it can be done in all modules QueryDSL Documentation (but I haven't been able to find out how to do it with Mongo)
here's the code snippet for hibernate
class CustomerDTO {
#QueryProjection
public CustomerDTO(long id, String name){
...
}
QCustomer customer = QCustomer.customer;
JPQLQuery query = new HibernateQuery(session);
List<CustomerDTO> dtos = qry.from(customer).list(new QCustomerDTO(customer.id, customer.name));
Any Ideas ?
This is currently not supported. Feel free to add a ticket for it into our Issue tracker.
The Lucene and Mongodb modules of Querydsl support only direct projections from the query root, but for custom projections something could be figured out.
I've just built a projection like this:
Criteria c1 = Criteria.where("field.name").is("val")
Criteria projection = Criteria.where("field").is(1)
BasicQuery query = new BasicQuery(c1.getCriteriaObject(), projection.getCriteriaObject())

Resources