Я хотел бы знать, есть ли способ переопределить метод удаления для некоторых из моих репозиториев 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)?
Заранее спасибо!
Нет, я не этого хотел.
В вашем случае код будет таким, как показано ниже:
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 в база данных.
Хорошо. Затем вы можете создать собственный интерфейс репозитория, а затем предоставить индивидуальную реализацию.
Это то, что я также прокомментировал в сообщении. Если я предоставлю нестандартную реализацию, мне придется реализовать все методы findByX, что является довольно большой дополнительной работой, и в этом случае я возился с SQL больше, чем мне бы хотелось :)
Нет, вам нужно создавать UserRepository и UserRepositoryCustom в индивидуальном порядке, вы можете добавлять методы, которые вы хотите предоставить индивидуальной реализации.
Хорошо, теперь я понимаю, о чем вы говорите, и да, я знаю, что такой подход возможен, но я надеялся, что будет существовать что-то более приятное. Я так и сделаю, если нет ничего лучше.
Не уверен, что понимаю вас достаточно ясно, но давайте попробуем:
... 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)?
Хорошо, похоже, что @ PreRemove / @ PostRemove работают с UserRepo.delete(myUser). Я думал, что они действовали для метода remove на EntityManager. Используется ли это за кулисами JpaRepository? Где можно узнать об этом больше? Большое спасибо!
Взгляните на эту статью: baeldung.com/database-auditing-jpa
В зависимости от того, что вы пытаетесь сделать, есть несколько способов сделать это:
Я предпочитаю использовать именование методов, если это возможно, имя метода становится длинным, но вы точно знаете, что он делает, глядя на него.
Дело в том, что мне действительно нужно переопределить метод удаления и сделать что-то в коде до того, как пользователь будет удален, так что только данные SQL могут не сработать.
Затем вы должны сделать это на уровне обслуживания, а не в репозитории.
Тогда я боюсь, что кто-то, не имеющий особого представления о том, что происходит, просто позвонит UserRepo.dele(myUser) и испортит данные в БД.
Тогда я думаю, что JpaRepositories у вас не работает. Они предназначены для основных операций CRUD, а не для добавления бизнес-логики.
Привет, вы можете написать свою собственную реализацию записи интерфейса с помощью EntityManager и Расширьте в своем интерфейсе вот образец:
На самом деле еще один способ написать что-то вроде:
User findByUsername(String username) // it will find the user by specific username
весенние данные создадут вам реализацию этого метода Таким же образом вы можете создать свой собственный метод удаления
Вот полезные ссылки:
По этой ссылке вы можете перейти к части 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), чем настраиваемое репо для удаления, но в конечном итоге я сделаю это, если необходимо :)
Обновленный ответ можете посмотреть)
Спасибо, но на самом деле я хочу вызвать какой-то код для объекта fasToBeDeleted, а затем удалить его, а не только SQL :)
public interface UserRepo extends JpaRepository<User, Long> {
@Modifying
@Query("delete from User u where u.email = ?1")
void deleteByEmail(String email);
}
Это не отменяет метод delete, который (я думаю) мне и нужно делать :)
Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода, так как это действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос для читателей в будущем, и эти люди могут не знать причины вашего предложения кода.
В дополнение к сообщению Рахилы Аслам:
В документации 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. Но мне придется пойти по этому пути, если ничего лучше не возможно :)
Если вы хотите сохранить поведение Spring для удаления, но хотите, чтобы какая-то логика выполнялась до или после, вы можете использовать методы интерфейса java8 по умолчанию и попробовать следующее:
public interface UserRepo extends JpaRepository<User, Long> {
default void customDelete(User user) {
// before logic
// ..
delete(user); // actual call to deletion
// after logic
// ..
}
}
Нет, это не убережет неосведомленного кодировщика от ошибочного вызова обычного удаления. И вы не можете писать код в интерфейсе, не так ли?
Начиная с java 8, да, вы можете. Посмотрите документы для получения дополнительной информации docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.ht ml
Пожалуйста, ознакомьтесь с проблемой ниже, как-то она связана: stackoverflow.com/questions/39923434/…