Пользовательский метод удаления в JpaRepository

Я хотел бы знать, есть ли способ переопределить метод удаления для некоторых из моих репозиториев JpaRepository без необходимости переопределения остальных методов.

В настоящее время у меня есть что-то вроде

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

    findUserByEmail(String email);

    // etc...
}

И я хотел бы переопределить метод delete(T Entity) в CrudRepository. Для этого я попытался реализовать UserRepo, но затем мне нужно реализовать все findByX, и я действительно не нашел ничего о том, как это правильно сделать.

Можно ли добавить аннотацию к функции в классе Entity, чтобы она запускалась при вызове UserRepo.delete(myUser)?

Заранее спасибо!

Пожалуйста, ознакомьтесь с проблемой ниже, как-то она связана: stackoverflow.com/questions/39923434/…

Raheela Aslam 08.11.2018 11:53

Нет, я не этого хотел.

epsilonmajorquezero 08.11.2018 12:12
2
2
6 357
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

В вашем случае код будет таким, как показано ниже:

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
    }
}

Да, я знаю, что могу это сделать, но это delete(T entity), который я хочу переопределить, чтобы не дать неосведомленному разработчику вызвать его вместо deleteByEmail с настраиваемым поведением и беспорядками, потому что delete не делает то, что должен, но все же удаляет Entity в база данных.

epsilonmajorquezero 08.11.2018 12:03

Хорошо. Затем вы можете создать собственный интерфейс репозитория, а затем предоставить индивидуальную реализацию.

Raheela Aslam 08.11.2018 12:07

Это то, что я также прокомментировал в сообщении. Если я предоставлю нестандартную реализацию, мне придется реализовать все методы findByX, что является довольно большой дополнительной работой, и в этом случае я возился с SQL больше, чем мне бы хотелось :)

epsilonmajorquezero 08.11.2018 12:10

Нет, вам нужно создавать UserRepository и UserRepositoryCustom в индивидуальном порядке, вы можете добавлять методы, которые вы хотите предоставить индивидуальной реализации.

Raheela Aslam 08.11.2018 12:13

Хорошо, теперь я понимаю, о чем вы говорите, и да, я знаю, что такой подход возможен, но я надеялся, что будет существовать что-то более приятное. Я так и сделаю, если нет ничего лучше.

epsilonmajorquezero 08.11.2018 12:27
Ответ принят как подходящий

Не уверен, что понимаю вас достаточно ясно, но давайте попробуем:

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

Вы этого не сделаете, spring сгенерирует фрагмент JPQL, если вы назовете методы в своем интерфейсе с подходящей конвекцией, пожалуйста, посмотрите статьи это и это

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

Вы можете использовать аннотацию @PreRemove / @PostRemove для метода в своем классе сущности:

@PreRemove / @PostRemove
public void someMethod() { ... }

Что касается первого: если я implementUserRepo, то я должен реализовать все методы, которые у меня есть. Итак, если я выставляю findByEmail в UserRepo, то в UserRepoImpl, где я могу переопределить delete, я должен закодировать findByEmail. Что касается @ PreRemove / @ PostRemove, я видел их, но они действуют на EntityManager.remove(), если я не ошибаюсь. Будет ли это работать в UserRepo.delete(myUser)?

epsilonmajorquezero 08.11.2018 12:08

Хорошо, похоже, что @ PreRemove / @ PostRemove работают с UserRepo.delete(myUser). Я думал, что они действовали для метода remove на EntityManager. Используется ли это за кулисами JpaRepository? Где можно узнать об этом больше? Большое спасибо!

epsilonmajorquezero 08.11.2018 14:08

Взгляните на эту статью: baeldung.com/database-auditing-jpa

Kamil W 08.11.2018 14:24

В зависимости от того, что вы пытаетесь сделать, есть несколько способов сделать это:

Я предпочитаю использовать именование методов, если это возможно, имя метода становится длинным, но вы точно знаете, что он делает, глядя на него.

Дело в том, что мне действительно нужно переопределить метод удаления и сделать что-то в коде до того, как пользователь будет удален, так что только данные SQL могут не сработать.

epsilonmajorquezero 08.11.2018 12:12

Затем вы должны сделать это на уровне обслуживания, а не в репозитории.

lgaleazzi 08.11.2018 12:14

Тогда я боюсь, что кто-то, не имеющий особого представления о том, что происходит, просто позвонит UserRepo.dele(myUser) и испортит данные в БД.

epsilonmajorquezero 08.11.2018 12:22

Тогда я думаю, что JpaRepositories у вас не работает. Они предназначены для основных операций CRUD, а не для добавления бизнес-логики.

lgaleazzi 08.11.2018 12:33

Привет, вы можете написать свою собственную реализацию записи интерфейса с помощью EntityManager и Расширьте в своем интерфейсе вот образец:

На самом деле еще один способ написать что-то вроде:

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

весенние данные создадут вам реализацию этого метода Таким же образом вы можете создать свой собственный метод удаления

Вот полезные ссылки:

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

По этой ссылке вы можете перейти к части 2.3 QueryMethods:

Вы также можете определить @NameQuery в своем классе сущности:

@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);
}

Вот ссылка с образцом:

Я думаю это полезно для тебя

Я ожидал чего-то более приятного (например, вызова некоторого кода в самом Entity), чем настраиваемое репо для удаления, но в конечном итоге я сделаю это, если необходимо :)

epsilonmajorquezero 08.11.2018 12:29

Обновленный ответ можете посмотреть)

Mykhailo Moskura 08.11.2018 12:55

Спасибо, но на самом деле я хочу вызвать какой-то код для объекта fasToBeDeleted, а затем удалить его, а не только SQL :)

epsilonmajorquezero 08.11.2018 13:02
public interface UserRepo extends JpaRepository<User, Long> {
    @Modifying
    @Query("delete from User u where u.email = ?1")
    void deleteByEmail(String email);

}

Это не отменяет метод delete, который (я думаю) мне и нужно делать :)

epsilonmajorquezero 08.11.2018 12:05

Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода, так как это действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос для читателей в будущем, и эти люди могут не знать причины вашего предложения кода.

Luca Kiebel 08.11.2018 13:27
stackoverflow.com/questions/43665090/…
Faisal Mk 09.11.2018 06:05

В дополнение к сообщению Рахилы Аслам:

В документации Spring-data есть пример того, как вы можете переопределить стандартные методы репозитория, например:

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> {
}

Вы можете прочитать об этом здесь: https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#repositories.custom-implementations

UPD: Прочтите его внимательно, потому что есть некоторые важные вещи, например Самая важная часть имени класса, соответствующая интерфейсу фрагмента, - это постфикс Impl.

Также в документации говорится: Пользовательские реализации имеют более высокий приоритет, чем аспекты базовой реализации и репозитория.

Да, я видел это в документации, но очень надеялся, что есть более простой способ, похожий на тот, который предложил @Kamil W. Но мне придется пойти по этому пути, если ничего лучше не возможно :)

epsilonmajorquezero 08.11.2018 12:25

Если вы хотите сохранить поведение Spring для удаления, но хотите, чтобы какая-то логика выполнялась до или после, вы можете использовать методы интерфейса java8 по умолчанию и попробовать следующее:

public interface UserRepo extends JpaRepository<User, Long> {

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

}

Нет, это не убережет неосведомленного кодировщика от ошибочного вызова обычного удаления. И вы не можете писать код в интерфейсе, не так ли?

epsilonmajorquezero 08.11.2018 13:00

Начиная с java 8, да, вы можете. Посмотрите документы для получения дополнительной информации docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.ht‌ ml

Elgarni 08.11.2018 13:05

Другие вопросы по теме