Spring Data JPA Delete und Beziehungen

1. Übersicht

In diesem Tutorial sehen wir uns an, wie das Löschen in Spring Data JPA erfolgt.

2. Beispielentität

Wie wir aus der Spring Data JPA-Referenzdokumentation wissen, bieten uns Repository-Schnittstellen grundlegende Unterstützung für Entitäten.

Wenn wir eine Entität haben, wie ein Buch :

@Entity public class Book { @Id @GeneratedValue private Long id; private String title; // standard constructors // standard getters and setters }

Anschließend können wir das CrudRepository von Spring Data JPA erweitern , um Zugriff auf CRUD-Operationen in Book zu erhalten :

@Repository public interface BookRepository extends CrudRepository {}

3. Aus dem Repository löschen

CrudRepository enthält unter anderem zwei Methoden: deleteById und deleteAll .

Testen wir diese Methoden direkt in unserem BookRepository :

@RunWith(SpringRunner.class) @SpringBootTest(classes = {Application.class}) public class DeleteFromRepositoryUnitTest { @Autowired private BookRepository repository; Book book1; Book book2; List books; // data initialization @Test public void whenDeleteByIdFromRepository_thenDeletingShouldBeSuccessful() { repository.deleteById(book1.getId()); assertThat(repository.count()).isEqualTo(1); } @Test public void whenDeleteAllFromRepository_thenRepositoryShouldBeEmpty() { repository.deleteAll(); assertThat(repository.count()).isEqualTo(0); } }

Beachten Sie , dass CrudRepository auch für andere Spring Data JPA-Schnittstellen wie JpaRepository oder PagingAndSortingRepository verwendet wird , obwohl wir CrudRepository verwenden.

4. Abgeleitete Löschabfrage

Wir können auch Abfragemethoden zum Löschen von Entitäten ableiten. Es gibt eine Reihe von Regeln zum Schreiben, aber konzentrieren wir uns nur auf das einfachste Beispiel.

Eine abgeleitete Löschabfrage muss mit deleteBy beginnen , gefolgt vom Namen der Auswahlkriterien. Diese Kriterien müssen im Methodenaufruf angegeben werden.

Angenommen, wir möchten Bücher nach Titel löschen . Unter Verwendung der Namenskonvention, würden wir beginnen mit deleteBy und Liste Titel als unsere Kriterien:

@Repository public interface BookRepository extends CrudRepository { long deleteByTitle(String title); }

Der Rückgabewert vom Typ long gibt an, wie viele Datensätze die Methode gelöscht hat.

Schreiben wir einen Test und stellen sicher, dass er korrekt ist:

@Test @Transactional public void whenDeleteFromDerivedQuery_thenDeletingShouldBeSuccessful() { long deletedRecords = repository.deleteByTitle("The Hobbit"); assertThat(deletedRecords).isEqualTo(1); }

Das Fortbestehen und Löschen von Objekten in JPA erfordert eine Transaktion. Aus diesem Grund sollten wir bei Verwendung dieser abgeleiteten Löschabfragen eine @ Transactional- Annotation verwenden, um sicherzustellen, dass eine Transaktion ausgeführt wird. Dies wird in der ORM mit Spring-Dokumentation ausführlich erläutert.

5. Benutzerdefinierte Abfrage löschen

Die Methodennamen für abgeleitete Abfragen können sehr lang werden und sind auf nur eine Tabelle beschränkt.

Wenn wir etwas Komplexeres benötigen, können wir eine benutzerdefinierte Abfrage mit @Query und @Modifying zusammen schreiben .

Lassen Sie uns den entsprechenden Code für unsere abgeleitete Methode von früher überprüfen:

@Modifying @Query("delete from Book b where b.title=:title") void deleteBooks(@Param("title") String title);

Auch hier können wir mit einem einfachen Test überprüfen, ob es funktioniert:

@Test @Transactional public void whenDeleteFromCustomQuery_thenDeletingShouldBeSuccessful() { repository.deleteBooks("The Hobbit"); assertThat(repository.count()).isEqualTo(1); }

Beide oben vorgestellten Lösungen sind ähnlich und erzielen das gleiche Ergebnis. Sie verfolgen jedoch einen etwas anderen Ansatz.

Die @Query- Methode erstellt eine einzelne JPQL-Abfrage für die Datenbank. Im Vergleich dazu führen die deleteBy- Methoden eine Leseabfrage aus und löschen dann jedes der Elemente einzeln .

6. In Beziehungen löschen

Mal sehen, was passiert, wenn wir Beziehungen zu anderen Entitäten haben.

Angenommen , wir haben eine Kategorie Einheit, die eine hat OneToMany Verbindung mit dem Buch Einheit:

@Entity public class Category { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) private List books; // standard constructors // standard getters and setters }

Das CategoryRepository kann nur eine leere Schnittstelle sein, die CrudRepository erweitert :

@Repository public interface CategoryRepository extends CrudRepository {}

Wir sollten auch die ändern Buch Unternehmen diesen Verein zu reflektieren:

@ManyToOne private Category category;

Fügen wir nun zwei Kategorien hinzu und ordnen Sie sie den Büchern zu, die wir derzeit haben. Wenn wir nun versuchen, die Kategorien zu löschen, werden auch die Bücher gelöscht:

@Test public void whenDeletingCategories_thenBooksShouldAlsoBeDeleted() { categoryRepository.deleteAll(); assertThat(bookRepository.count()).isEqualTo(0); assertThat(categoryRepository.count()).isEqualTo(0); }

Dies ist jedoch nicht bidirektional. Das heißt, wenn wir die Bücher löschen, sind die Kategorien immer noch da:

@Test public void whenDeletingBooks_thenCategoriesShouldAlsoBeDeleted() { bookRepository.deleteAll(); assertThat(bookRepository.count()).isEqualTo(0); assertThat(categoryRepository.count()).isEqualTo(2); }

Wir können dieses Verhalten ändern, indem wir die Eigenschaften der Beziehung ändern, z. B. den CascadeType .

7. Fazit

In diesem Artikel haben wir verschiedene Möglichkeiten zum Löschen von Entitäten in Spring Data JPA untersucht. Wir haben uns die bereitgestellten Löschmethoden aus CrudRepository sowie unsere abgeleiteten oder benutzerdefinierten Abfragen mithilfe der @Query- Annotation angesehen.

Wir haben uns auch angesehen, wie das Löschen in Beziehungen erfolgt. Wie immer finden Sie alle in diesem Artikel erwähnten Codefragmente in unserem GitHub-Repository.