Обработка мягких удалений с помощью Spring JPA
У меня есть таблица, определенная как …
id, ..., active
Active – это флаг soft-delete и всегда 1
или 0
. В долгосрочной перспективе это может уйти в пользу исторической таблицы.
public interface StuffRepository extends JpaRepository {}
В коде мы всегда используем активные записи. Есть ли способ заставить Spring всегда добавлять условие active=1
к запросам, сгенерированным для этого репозитория? Или, что еще лучше, позвольте мне расширить грамматику, используемую для генерации запросов?
- Как сохранить типы JSR-310 с помощью Spring Data JPA?
- POSTing ассоциация суб-ресурсов @OneToMany в Spring Data REST
- setMaxResults для annotations Spring-Data-JPA?
- Данные Spring jpa- Определен бит bean с именем 'entityManagerFactory'; Инъекция автоуведомленных зависимостей не удалась
- В чем разница между интерфейсами CrudRepository и JpaRepository в Spring Data JPA?
Я понимаю, что я могу создавать named @queues
всюду, но потом теряю удобство сгенерированных запросов. Я также хочу избежать загрязнения интерфейса «активными» методами.
Я использую Hibernate 4.2 в качестве моей реализации JPA, если это имеет значение.
- Как проверить поддержку декларативного кэширования Spring в хранилищах Spring Data?
- Spring JPA выбирает определенные столбцы
- При использовании методов getOne и findOne Spring Data JPA
- Весовые данные JPA-запрос с параметрическими свойствами
- Отключить язык приложений гипертекста (HAL) в JSON?
- Spring-Data FETCH JOIN with Paging не работает
- обновление логического значения в данных весны jpa с использованием @Query, с гибернацией
- Можно ли использовать исходный SQL в Spring Repository
Это старый вопрос, и вы, вероятно, уже нашли ответ. НО, для всех программистов Spring / JPA / Hibernate, ищущих ответа –
Скажем, у вас есть сущность. Собака:
@Entity public class Dog{ ......(fields).... @Column(name="is_active") private Boolean active; }
и хранилище:
public interface DogRepository extends JpaRepository { }
Все, что вам нужно сделать, это добавить аннотацию @Where на уровне сущности, в результате чего:
@Entity @Where(clause="is_active=1") public class Dog{ ......(fields).... @Column(name="is_active") private Boolean active; }
Все запросы, выполняемые репозиторием, будут автоматически отфильтровывать «неактивные» строки.
@Where(clause="is_active=1")
– это не лучший способ обработки мягкого удаления с помощью весенних данных jpa.
Во-первых, он работает только с спящим режимом.
Во-вторых, вы никогда не сможете получать мягкие удаленные объекты с данными весны.
Мое решение задано с помощью весенних данных. Выражение #{#entityName}
может использоваться для общего репозитория, представляющего конкретное имя типа объекта.
И код будет выглядеть так:
//Override CrudRepository or PagingAndSortingRepository's query method: @Override @Query("select e from #{#entityName} e where e.deleteFlag=false") public List findAll(); //Look up deleted entities @Query("select e from #{#entityName} e where e.deleteFlag=true") public List recycleBin(); //Soft delete. @Query("update #{#entityName} e set e.deleteFlag=true where e.id=?1") @Modifying public void softDelete(String id);
На основе 易天明 ответа я создал реализацию CrudRepository с помощью переопределенных методов для мягкого удаления:
@NoRepositoryBean public interface SoftDeleteCrudRepository extends CrudRepository { @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.isActive = true") List findAll(); @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id in ?1 and e.isActive = true") Iterable findAll(Iterable ids); @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id = ?1 and e.isActive = true") T findOne(ID id); //Look up deleted entities @Query("select e from #{#entityName} e where e.isActive = false") @Transactional(readOnly = true) List findInactive(); @Override @Transactional(readOnly = true) @Query("select count(e) from #{#entityName} e where e.isActive = true") long count(); @Override @Transactional(readOnly = true) default boolean exists(ID id) { return findOne(id) != null; } @Override @Query("update #{#entityName} e set e.isActive=false where e.id = ?1") @Transactional @Modifying void delete(Long id); @Override @Transactional default void delete(T entity) { delete(entity.getId()); } @Override @Transactional default void delete(Iterable entities) { entities.forEach(entitiy -> delete(entitiy.getId())); } @Override @Query("update #{#entityName} e set e.isActive=false") @Transactional @Modifying void deleteAll(); }
Его можно использовать с BasicEntity:
@MappedSuperclass public abstract class BasicEntity { @Column(name = "is_active") private boolean isActive = true; public abstract Long getId(); // isActive getters and setters... }
И конечное лицо:
@Entity @Table(name = "town") public class Town extends BasicEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "town_id_seq") @SequenceGenerator(name = "town_id_seq", sequenceName = "town_id_seq", allocationSize = 1) protected Long id; private String name; // getters and setters... }
В текущих версиях (до 1.4.1) нет специальной поддержки для мягких удалений в Spring Data JPA. Тем не менее, я настоятельно рекомендую вам играть с ветвью функций для DATAJPA-307, поскольку это функция, которая в настоящее время работает для предстоящей версии.
Чтобы использовать текущее обновление состояния, вы используете версию 1.5.0.DATAJPA-307-SNAPSHOT и убедитесь, что вы разрешите ей использовать специальную версию Spring Data Commons, которую она должна работать. Вы должны быть в состоянии следовать образцу тестового примера, мы должны видеть, как заставить это работать.
PS: Я обновлю вопрос, как только мы закончим работу над этой функцией.
Вы можете простираться от SimpleJpaRepository и создавать свой собственный repository, где вы можете определить функциональность мягкой функциональности в общем виде.
Вам также необходимо создать пользовательский JpaRepositoryFactoryBean и включить его в свой основной class.
Вы можете проверить мой код здесь https://github.com/dzinot/spring-boot-jpa-soft-delete
Я предлагаю вам использовать представление базы данных (или эквивалент в Oracle), если вы не хотите импортировать annotations спящего режима. В mySQL 5.5 эти представления могут быть обновляемыми и вставляемыми, если критерии фильтра просты, как активные = 1
создать или заменить view active_stuff как select * from Stuff, где active = 1;
Является ли это хорошей идеей, вероятно, зависит от вашей базы данных, но она отлично работает в моей реализации.
Undeleting требовал дополнительный объект, который напрямую обращался к «Stuff», но затем был бы @Where