Understanding repositories in Spring Data - spring

I want to create a "generic" repository that query data from multiple entities. If I do that:
#Repository
public interface MyRepository {
#Query("select r from Role r")
List<Role> getRoles();
}
I get an error because Spring doesn't find an implementation to inject when a MyRepository instance is required. So far, so good. Now, If I do this:
#Repository
public interface MyRepository extends JpaRepository {
#Query("select r from Role r")
List<Role> getRoles();
}
I get an error because Object is not a JPA managed type (JpaRepository is generic). Ok, again. If I do this:
#Repository
public interface MyRepository extends JpaRepository<User, String> {
#Query("select r from Role r")
List<Role> getRoles();
}
It works. Why? I'm declaring a JpaRepository for entity User, not Role. Why does JpaRepository need a concrete entity even when the queries will be against another one?

Every repository in Spring Data has to extend the Repository interface, that is a generic interface, so you always have to specify the entity you are gonna work with and you can't do anything about it because it is how Spring Data is implemented. You can find more information here about creating repositories:
http://docs.spring.io/spring-data/jpa/docs/1.4.0.M1/reference/html/repositories.html
On the other hand, of course you can specify one entity to the repository and then add methods that return other type of entities because in your interface you can add whatever you want (also notice that Repository interface has no methods). But if you want to use the methods of the parent interface you have to use the entity you specified.
In your example, you could do what #M. Deinum suggested and create a JpaRepository<Role, Long> and use the findAll query, that makes much more sense. Using a JpaRepository<User, String> as you are doing is just a misuse of the framework.

Related

Writing generic spring jpa repository for all entities

I am working on Spring Boot application.
We have Service Layer,Rest Controller and Dao as repository.
I have 20 to 30 tables in my database and I dont want to create repository for each entity and extends that to CrudRepository.
ex : User is an Entity, to perform persistance operations on User, I have to create UserRepository which extends CrudRepository.
Same with Department, Company etc...
What i want to do is, I will write a BaseRepository which gonna extend CrudRepository, base repository should accept all entities and do persistance operations.
Is there a way to that ??
Don't extend CrudRepository it's functionality is all tied to the generic type, it'd be hacky to extend it for a generic implementation. You probably just want something simple which uses the JPA entity manager directly:
import javax.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
public class GenericRepository {
#Autowired
private EntityManager entityManager;
public <T, ID> T findById(Class<T> type, ID id) {
return entityManager.find(type, id);
}
}

How to stream resultsets in spring Data JPA with custom criteria

I'm working on a POC, using Spring Boot 2.0.5, Spring Data JPA using Hibernate. I'm trying to implement a way to stream the result sets for a custom criteria. I have seen examples like
public interface MyRepository implements JPARepository<Person,Long>{
#Query("select p from person p")
Stream<Person> findAll();
}
However I'm extending SimpleJPARepository and want to get results as a stream using a Criteria something like
Stream<Person> findAll(Criteria criteria);
Since I'm using class that extends SimpleJPARepository, I need to provide my implementation. But are there any methods in SimpleJPARepository or its parent classes, that can provide me default implementation using the criteria I provide. Any reference to such example is much helpful.
Also, in some examples I see that #NoRepositoryBean is used and in some cases #Repository. I'm confused between these two and which one should I use and why?
As per Spring Data JPA specifications Spring Data JPA, this is how you can create Criteria queries.
Step 1: extend your repository interface with the JpaSpecificationExecutor interface, as follows:
public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor {
…
}
Step 2: the findAll method returns all entities that match the specification, as shown in the following example:
List<T> findAll(Specification<T> spec);
Step 3: The Specification interface is defined as follows:
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}

what is the use of CrudRepository in springboot

#RepositoryRestResource
public interface StudentRepository extends CrudRepository<Student, Long>
{
public List<Student> findById(long id);
//#Query("select s from Student s where s.age <= ?")
public List<Student> findByAgeLessThanEqual (long age);
}
what does <Student, long> mean in the CrudRepository<Student, long> and what are the various parameters that can be passed to cruderepository.
The main idea of CrudRepository is to give you opportunity to use main operations with data without creating your own implementation. You just create needed methods and for most simple cases Spring will create implementation for you (if you use right naming convention for your methods).
First parameter (Student in your case) is a type of entity with which current Repository is working, second parameter (Long in your case) is a type of Id in this entity.
CrudRepository provides methods for the CRUD operations. This interface extends the Repository interface. If you are extending the CrudRepository, there is no need for implementing your own methods.
If do not want data from custom parameter, you have to write custom query for it.
you can use only that parameters which is their in your CrudRepository.

Deciding which implementation to inject

I have a Spring project, split into several modules.
data access library (spring-data-jpa; entities and repositories)
security library (spring-security; including an extended repository with #PreAuthorize annotations)
web project (depends on both libraries)
batch project (depends only on data, since there's no user to authenticate in Spring)
So in the data access library, I have this interface:
#Repository
public interface ItemRepository extends PagingAndSortingRepository<Item, Long> {
List<Item> findAll();
Item findById(Long id);
}
And in the security library:
#Repository
public interface SecuredItemRepository extends ItemRepository {
#PreAuthorize("hasRole('ROLE_ADMIN')")
List<Item> findAll();
#PreAuthorize("hasRole('ROLE_ADMIN')")
Item findById(Long id);
}
When I #Autowire an ItemRepository, I would like it to use SecuredItemRepository if it's available, and ItemRepository if not.
Is there a way to declare the SecuredItemRepository as the default choice, or first in the list of ItemRepository implementations to grab? I'd rather not specify the implementation in every location that I need to access the database.
And of course, two seconds later I find the answer. I needed to annotate SecuredItemRepository with this:
#Priority(value = Ordered.HIGHEST_PRECEDENCE)

Can I choose the name of my jpa repository?

I have to name my interface that extends the CrudRepository
with a spacific name (I use spring and Jpa)
i.e.
public interface UserRepository extends CrudRepository<User, Long> {}
so in this case I have a Entity with name UserRepository
I tried annotation
#Entity(name="UserCustomRepository")
public interface UserRepository extends CrudRepository<User, Long> {}
but it doesn't work...
Apparently it's not possible according to the documentation, see 1.3.3.1. XML Configuration:
Each of these beans will be registered under a bean name that is derived from the interface name, so an interface of UserRepository would be registered under userRepository.
Why do you need a custom name? Besides your example with #Entity(name="UserCustomRepository") is completely broken, #Entity is used to mark JPA entities, not Spring beans/repositories.

Resources