Custom repository - spring-boot

I have in my project a few entity that have the same property (for sample 'name') so, it's possible to create a repository with a custom select to use in that's entities? so instead I extend my repository from JpaRepository I extend MyCustomJpaRepository and the MyCustomJpaRepository extends the JpaRepository to grant the basic functions from JpaRepository too?
tks

Yes you can define a common interface repository which extends JpaRepository by marking it with the annotation #NoRepositoryBean:
#NoRepositoryBean
public interface BaseRepository<T extends BaseEntity, ID extends Serializable> extends JpaRepository<T, ID> {
//common methods
}
However, you still must have a dedicated interface for each of your concrete entities which extend this custom interface.

Related

Dynamic JPA Projections with extended interface and generics

I am looking to use Spring JPA Dynamic Projections to limit the number of fields returned from queries. The table I'm using is wide, but the projection still contains around 10 fields. Therefore I am trying to use Dynamic Projections. The problem seems to be with trying to specify the methods in the repository interface since I first have an interface that extends the JpaRepository using an abstract class and then I have an interface the extends that one using the actual class.
I have tried various approaches to limiting the number of fields and this one seems to be the closest to what I want to use.
Here is my repository on the abstract class User:
#NoRepositoryBean
public interface UserRepository <T extends User> extends JpaRepository<T,
Long>{
<S extends T> S findByLoginName(String loginName);
}
Here is my actual repository on the actual class ConcreteUser:
#Repository
public interface ConcreteUserRepository extends UserRepository<ConcreteUser> {
}
In my service class implementation I have a method call that looks like this:
ConcreteUser user = this.userRepository.findByLoginName(loginName);
This of course returns a large number of fields, so I created an interface that contains the subset of fields that I want called UserProfile. The field names are exactly the same as those in the ConcreteUser. I then added 'implements UserProfile' to the User class. I don't know if that is necessary, but I'm trying to get the generics working so that I can do something like this:
#NoRepositoryBean
public interface UserRepository <T extends User> extends JpaRepository<T,
Long>{
<S extends T> S findByLoginName(String loginName, Class<S> clazz);
}
and then call it like this:
ConcreteUser user = this.userRepository.findByLoginName(loginName, ConcreteUser.class);
UserProfile profile = this.userRepository.findByLoginName(loginName, UserProfile.class;
I've tried various approaches with the generics. I've also tried using my DTO class UserProfileDTO instead of the UserProfile interface.
I am having problems with getting the Generics correct because of the extra level of abstraction.

Deprecated QuerydslJpaReposiotry does not work anymore

I have a custom repository that needs the functionality of Querydsl as well as PagingAndSortingRepository. Till now my custom repository was like
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QuerydslPredicateExecutor<T> {
// Overriden methods
}
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
// Overriden implementations of methods defined in the interface
}
The great thing about this was that my custom implementation was not very different from the default implementation provided by QuerydslJpaRepository and thus I would use the super class methods with some modifications in mine like
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
#Override
#NonNull
public Optional<T> findOne(#NonNull Predicate predicate) {
return super.findOne(modifierMethod(predicate));
}
#Override
#NonNull
public <U extends T> U save(#NonNull U entity) {
return super.save(otherModifierMethod(entity, false));
}
#Override
#NonNull
public <S extends T> S saveCustom(#NonNull S entity) {
return super.save(otherModifierMethod(entity, false));
}
}
Note that I also have a saveCustom defined by me in the custom interface and I am providing its implementation with the help of the parent class.
This worked great but after Spring Boot 2.1, QuerydslJpaRepository has been deprecated in favour of QuerydslJpaPredicateExecutor. Now this class does not provide implementations of save or delete and thus I cannot use the SimpleJpaRepository methods if my implementation class inherits from QuerydslJpaPredicateExecutor.
In short, I need to reimpelement query and save/delete methods in my custom repository along with some custom methods of mine and I don't want to implement them from scratch. The current deprecation means my implementation can extend either from QuerydslJpaPredicateExecutor which provides implementation of query methods only or from SimpleJpaRepository which means I lose the functionality of querydsl in my implementation.
What I've done till now
To work around this I have created 2 repositories
#NoRepositoryBean
public interface CustomPagingSortingRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
// Only overrides save and delete type of methods and includes my customSave method
#NoRepositoryBean
public interface CustomQuerydslRepository<T, ID> extends QuerydslPredicateExecutor<T> {
// Overrides all methods of the superclass and includes any custom methods of mine
}
and I have implemented them separately like
#NoRepositoryBean
public class CustomPagingSortingRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomPagingSortingRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
#NoRepositoryBean
public class CustomQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaPredicateExecutor<T> implements CustomQuerydslRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
and I inherit these 2 interfaces into my custom interface
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends CustomPagingSortingRepository<T,ID>,CustomQuerydslRepository<T, ID> {
}
I thought this would work but this throws a type error which on close inspection I found to be because Spring is trying to create an implementation of customSave by itself and since it doesn't understand what this method has to do, it throws an error.
I am really in a fix now since the deprecated way was extremely clean and I don't want to implement half a dozen Beans for this to work.
P.S.
I have been thinking using Composition instead of Inheritance to get a handle to SimpleJpaRepository and QuerydslJpaPredicateExecutor and use the methods in them that way but I have a feeling this is going to be against injection and a bad practice.

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.

How to add custom method to Spring repository?

Currently, here is my way to add custom method to one Spring Repository:
- firstly, create 1 interfaces extended from JPARepository along with my interface like this
interface MyRepository extends extends JpaRepository<Model, ID>, QueryDslPredicateExecutor<Model.class>, MyRepositoryCustom
then to create MyRepositoryCustom interface and its implementations
intefaces MyRepositoryCustom{
void myMethodHere();
}
class MyRepositoryImpl implement MyRepositoryCustom {
void myMethodHere(){
// do somethong
}
}
The problem is now that I want to reduce the amount of class, so is there any way to add custom methods with only 1 interface and 1 implement class.
If you want to implement the same custom method for all repositories in your app you have to:
Create base Repository interface by extending Repository Interface
Implement method in base Repository interface
Implement Custom RepositoryFactoryBean
Specify custom RepositoryFactoryBean in #EnableJpaRepositories annotation in configuration.
More details, for example, you can find here: http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-adding-custom-methods-into-all-repositories/

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