Limit findAll possible with Spring? - spring

Is it possible with Springs auto implemented repositories to limit the result size of the findAll method?
I'm trying to have something like the following declared in the interface:
List<XY> findAllTopTen();
Unfortunatelly, it doesn't work (this) way...

If you dont have a Pageable object that came from your controller and just need to get X amount of objects from DB, you can do the following:
First, your Repository class has to extend JpaRepository<T, ID> so it wil be able to query using a Pageable object.
Second, you can define a Pageable object this way:
Pageable limit = PageRequest.of(0,10);
return repository.findall(limit);
In this case, the query would return the first 10 objects.
You can find more info here (Scroll down to 4.1, Example 4)
Note that the example actually extends PagingAndSortingRepository but JpaRepository contains all the methods from PagingAndSortingRepository and has additional functions aswell.
Edit: Thanks to #Zunnii for pointing out that new PageRequest() is now deprecated. I edited the snippet above to reflect that.

Pass a Pageable as a parameter like following:
Page<x> findAll(Pageable pageable);

You need to explicitly specify the ordering, otherwise Spring Data JPA has no way of deciding what criteria it should use. For instance:
List<XY> findAllTopTenByAge();
See more details in the official documentation.

Related

How can I check QueryHint work or not?

Spring Data JPA allows placing #QueryHints annotation on the interface method and can be applied to the methods annotated with #Query and without such.
#QueryHints(#javax.persistence.QueryHint(name="org.hibernate.fetchSize", value="50"))
List<Foo> findAll();
How can I check know for sure that hint was honored?

How to Use sorting in Spring Data Rest GET method

When I create any repository in spring framework like following it gives method by default to get all records of the entity using this API
GET : http://localhost:3000/api/addresses
It sends data from ascending order But If I want my data in descending order than How can I specify this ?
Address Repository
public interface AddressRepository extends JpaRepository<Address, Long>
{
}
Perhaps,you can :
localhost:3000/api/addresses?sort={property},desc
this will help you sort by property desc
You can also specify this as part of your request, take a look at documentation here Sorting.
Also please take a look at similar answer here.
Try inside the AddressRepository class something like:
public List<Address> findAllByOrderByIdDesc();
of course you can change the "ById" part with any other field you want to use for sorting.

How to use declare Stream as return type when dealing with JPA Specification and spring-data-jpa

I'm wondering if I can use JPA specification predicates in custom queries?
I've tried but with no success.
Let's say I have an Entity Customer and a repository:
#Repository
public interface CustomerRepository
extends JpaRepository<Customer, Long>,
JpaSpecificationExecutor<Customer> {
}
Querying like this is OK
#Query("select c from Customer c")
Stream<Customer> streamAllCustomers();
This is Not OK
Stream<Customer> streamAllCustomersWithFilter(Specification<Customer> filter);
Is there a way to achieve this ?
NB I know I can put params in the #Query but I would like to stay in the design of the current app and use Specifications all the way.
There is the way to stream data from Spring Data JPA that I use.
This approach is useful to process huge amount of data while avoiding high memory consumption, because whole query result is not loaded to memory.
Create custom individual repository with following implementation
public class YourCustomRepositoryImpl implements YourCustomRepository {
#PersistenceContext(unitName = "yorEntityManagerFactory")
private EntityManager em;
#Override
public Stream<SomeEntity> streamAll(Specification<SomeEntity> spec) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<SomeEntity> query = cb.createQuery(SomeEntity.class);
Root<SomeEntity> root = query.from(SomeEntity.class);
query.where(spec.toPredicate(root, query, cb));
return em.createQuery(query).getResultStream();
}
}
Sure, this requires JPA 2.2 supporting ORM framework (I used Hibernate 5.3).
Also, you should care to provide a connection to be alive while stream is being processed.
TL;DR;
No, and No, but manually Yes
I think issue DATAJPA-906 answers both of your questions
Question (from the title): How to use declare Stream as return type when dealing with JPA Specification and spring-data-jpa?
You don't, at least not in a directly supported way:
Support Java 8 Streams on JpaSpecificationExecutor
[..]
This unfortunately will have to wait for a 2.0 revamp as a Stream in the method signature would render the interface unloadable on versions of Java < 8.
Of course you can always add your custom methods including implementation.
Question Can I use JPA specification predicates in custom queries? (custom queries being queries defined using the #Query annotation
how would you even combine a CriteriaQuery defined through a Specification and a manually defined JPQL query?
In case the problem is not clear: If your custom query contains an inner select, wher should the Criteria from the specification go?
What you can do
Implement a custom method, returning a Stream and taking a specification as an argument, combine it with prepared specifications to call an existing method of the JpaSpecificationExecutor interface and convert the result to a Stream

Spring Data MongoDB: Specifying a hint on a Spring Data Repository find method

I am implementing a Spring Data Repository and having my repository extend the MongoRepository. I am looking for a way to specify a hint on my findBy methods so I can be control. I have seen several times when a non-optimal index would be picked as the winning plan.
This is what my repository looks like right now:
public interface AccountRepository extends MongoRepository<Account, ObjectId> {
#Meta(maxExcecutionTime = 60000L, comment = "Comment" )
public List<Account> findByUserIdAndBrandId(Long userId, Long brandId);
}
I researched a bunch and found that the JPARepository from spring data supports the #QueryHint annotation but I do not believe that annotation is supported for MongoDb. Is there a similar annotation I can specify on top of my findBy method to specify the hint?
MongoTemplate allows to specify a hint, however, I have a ton of findBy methods and I would hate to add an implementation underneath just to specify a hint.

How to handle a large set of data using Spring Data Repositories?

I have a large table that I'd like to access via a Spring Data Repository.
Currently, I'm trying to extend the PagingAndSortingRepository interface but it seems I can only define methods that return lists, eg.:
public interface MyRepository extends
PagingAndSortingRepository<MyEntity, Integer>
{
#Query(value="SELECT * ...")
List<MyEntity> myQuery(Pageable p);
}
On the other hand, the findAll() method that comes with PagingAndSortingRepository returns an Iterable (and I suppose that the data is not loaded into memory).
Is it possible to define custom queries that also return Iterable and/or don't load all the data into memory at once?
Are there any alternatives for handling large tables?
We have the classical consulting answer here: it depends. As the implementation of the method is store specific, we depend on the underlying store API. In case of JPA there's no chance to provide streaming access as ….getResultList() returns a List. Hence we also expose the List to the client as especially JPA developers might be used to working with lists. So for JPA the only option is using the pagination API.
For a store like Neo4j we support the streaming access as the repositories return Iterable on CRUD methods as well as on the execution of finder methods.
The implementation of findAll() simply loads the entire list of all entities into memory. Its Iterable return type doesn't imply that it implements some sort of database level cursor handling.
On the other hand your custom myQuery(Pageable) method will only load one page worth of entities, because the generated implementation honours its Pageable parameter. You can declare its return type either as Page or List. In the latter case you still receive the same (restricted) number of entities, but not the metadata that a Page would additionally carry.
So you basically did the right thing to avoid loading all entities into memory in your custom query.
Please review the related documentation here.
I think what you are looking for is Spring Data JPA Stream. It brings a significant performance boost to data fetching particularly in databases with millions of record. In your case you have several options which you can consider
Pull all data once in memory
Use pagination and read pages each time
Use something like Apache Spark
Streaming data using Spring Data JPA
In order to make Spring Data JPA Stream to work, we need to modify our MyRepository to return Stream<MyEntity> like this:
public interface MyRepository extends PagingAndSortingRepository<MyEntity, Integer> {
#QueryHints(value = {
#QueryHint(name = HINT_CACHEABLE, value = "false"),
#QueryHint(name = READ_ONLY, value = "true")
})
#Query(value="SELECT * ...")
Stream<MyEntity> myQuery();
}
In this example, we disable second level caching and hint Hibernate that the entities will be read only. If your requirement is different, make sure to change those settings accordingly for your requirements.

Resources