2

I'd like to know if there's a way of overriding the delete method for some of my JpaRepository's without having to override the rest of the methods.

Currently I have something like

public interface UserRepo extends JpaRepository<User, Long>
{
    findUserById(long id);

    findUserByEmail(String email);

    // etc...
}

And I'd like to override the delete(T Entity) method in CrudRepository. To do so I've tried implementing the UserRepo but then I have to implement all the findByX and haven't really find anything around on how to properly do that.

Is there any annotation to add to a function in the Entity class so it runs when you call UserRepo.delete(myUser)?

Thanks in advance!

7 Answers7

2

Not sure I understand you clear enough, but lets try:

... I have to implement all the findByX ...

You don't, spring will generate JPQL snippet if you name methods in your interface with suitable convection please take a look at this and this articles

... Is there any annotation to add to a function in the Entity class so it runs when you call UserRepo.delete(myUser)? ...

You can use @PreRemove / @PostRemove annotation on method in your entity class:

@PreRemove / @PostRemove
public void someMethod() { ... }
Kamil W
  • 2,230
  • 2
  • 21
  • 43
  • Regarding the first one: If I `implement` the `UserRepo` then I have to implement all the methods I have there. So if I'm exposing a `findByEmail` in the `UserRepo`, then in `UserRepoImpl` where I could override the `delete` I must code the `findByEmail`. Regarding the @PreRemove/@PostRemove, I saw those but they are acting on `EntityManager.remove()` if I'm not mistaken. Will that work in `UserRepo.delete(myUser)`? – epsilonmajorquezero Nov 08 '18 at 11:08
  • Ok, it seems that @PreRemove/@PostRemove work with the `UserRepo.delete(myUser)`. I though they acted for the `remove` method on the `EntityManager`. Is that being used behind the scenes by JpaRepository? Anywhere to read more about it? Much thanks! – epsilonmajorquezero Nov 08 '18 at 13:08
  • Take a look at this article: https://www.baeldung.com/database-auditing-jpa – Kamil W Nov 08 '18 at 13:24
2

In addition to Raheela Aslam post:

Spring-data documentation has an example of how you can override standard repository methods, for example:

interface CustomizedSave<T> {
  <S extends T> S save(S entity);
}

class CustomizedSaveImpl<T> implements CustomizedSave<T> {

  public <S extends T> S save(S entity) {
    // Your custom implementation
  }
}

interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}

You can read about it there: https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#repositories.custom-implementations

UPD: Read it carefully, because there are some important things, e.g The most important part of the class name that corresponds to the fragment interface is the Impl postfix.

Also the documentation says: Custom implementations have a higher priority than the base implementation and repository aspects.

  • Yeah, I saw that in the documentation but I really hoped there was an more simple way similar to the one proposed by @Kamil W. But I'll have to go that way if nothing better is possible :) – epsilonmajorquezero Nov 08 '18 at 11:25
1

If you want to keep Spring's behavior for deletion, but want to have some logic to be executed either before or after, you may utilize java8's interface default methods, and try the following :

public interface UserRepo extends JpaRepository<User, Long> {

    default void customDelete(User user) {
       // before logic
       // ..
       delete(user); // actual call to deletion
       // after logic
       // ..
     }

}
Elgarni
  • 236
  • 2
  • 5
  • Nope, that wouldn't prefent an unaware coder from calling regular delete by mistake. And you can't write code in an interface, can you? – epsilonmajorquezero Nov 08 '18 at 12:00
  • 1
    From java 8 onwards, yes you can. Look at docs for more info https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html – Elgarni Nov 08 '18 at 12:05
0

In your case code will be like as below:

public interface UserRepo extends JpaRepository<User, Long>
{
    findUserById(long id);

    findUserByEmail(String email);

    // etc...
}

public interface UserRepositoryCustom {

    void deleteByEmail(String email);
}

public interface UserRepositoryImpl implements UserRepositoryCustom {

    public void deleteByEmail(String email) {
        //provide your custom implimentation
    }
}
Raheela Aslam
  • 452
  • 2
  • 13
  • Yeah, I know I can do that but is the `delete(T entity)` that I want to override to prevent an unaware developer from calling it instead of the `deleteByEmail` with custom behaviour and messing stuff because `delete` is not doing what it should but still deleting the Entity in the data base. – epsilonmajorquezero Nov 08 '18 at 11:03
  • Ok Then you can create you custom Repository interface and then provide custom implementation. – Raheela Aslam Nov 08 '18 at 11:07
  • That's what I also commented on the post. If I provide a custom implementation then I have to implement all the `findByX` methodfs too which is quite a bit of extra work and me messing with SQL more than I'd like too in that case :) – epsilonmajorquezero Nov 08 '18 at 11:10
  • 1
    No you have to create UserRepository and UserRepositoryCustom in custom you can add methods that you want to provide custom implementation. – Raheela Aslam Nov 08 '18 at 11:13
  • Ok, now I understand what you emant and yeah, I know this approach is possible but hoped for something nicer to exist. I'll end up doing that if there's nothing better. – epsilonmajorquezero Nov 08 '18 at 11:27
0

There are several ways to do this depending on what you're trying to do:

I prefer to use method naming if possible, the method name gets long, but you know exactly what it does by looking at it.

lgaleazzi
  • 163
  • 1
  • 9
  • The thing is that I really need to override the delete method and do some stuff in the code before the User gets deleted so just SQL stuff may not do the whole trick. – epsilonmajorquezero Nov 08 '18 at 11:12
  • Then you should do that in the service layer, not in the repository. – lgaleazzi Nov 08 '18 at 11:14
  • 1
    Then I'm afraid someone without much idea of what's happening will come and just call `UserRepo.dele(myUser)` and mess up with the data in the DB. – epsilonmajorquezero Nov 08 '18 at 11:22
  • Then I guess JpaRepositories are not working out for you. They are there for basic CRUD operations, definitely not to add business logic. – lgaleazzi Nov 08 '18 at 11:33
0

Hi you can write your own Interface write implementation with EntityManager and extend in you interface here is the sample :

Actually one more way is writing by soemthing like :

 User findByUsername(String username) // it will find the user by specific username 

spring data will create you an implementation of this method The same way you can create your own delete method

Here is useful links:

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations

In this link you can go to part 2.3 QueryMethods:

You can also define @NameQuery in your entity class:

@Entity
@Table(name = "employee", schema="spring_data_jpa_example")
@NamedQuery(name = "Employee.yourMethodQueryName",
        query = "yourQuery"
)
public class Employee {}

@Repository
public interface EmployeeRepository extends JpaRepository<Employee,Long> {

    List<Employee> yourMethodQueryName(Your list of params);
}

Here is link with sample:

I think this is helpful for you

Mykhailo Moskura
  • 2,073
  • 1
  • 9
  • 20
0
public interface UserRepo extends JpaRepository<User, Long> {
    @Modifying
    @Query("delete from User u where u.email = ?1")
    void deleteByEmail(String email);

}
Faisal Mk
  • 71
  • 5
  • That wouldn't override the `delete` method which is what (I think) I need to do :) – epsilonmajorquezero Nov 08 '18 at 11:05
  • While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Luca Kiebel Nov 08 '18 at 12:27
  • https://stackoverflow.com/questions/43665090/why-do-we-have-to-use-modifying-annotation-for-queries-in-data-jpa – Faisal Mk Nov 09 '18 at 05:05