Java >> Java Tutorial >  >> Tag >> Spring

Spring Data JPA Tutorial:Hinzufügen benutzerdefinierter Methoden zu allen Repositorys

Im vorherigen Teil dieses Tutorials haben wir gelernt, wie wir benutzerdefinierte Methoden zu einem einzigen Repository hinzufügen können.

Obwohl dies eine sehr nützliche Fähigkeit ist, hilft sie uns nicht, wenn wir dieselbe Methode in alle Repositories unserer Anwendung einfügen müssen.

Glücklicherweise bietet Spring Data eine Möglichkeit, benutzerdefinierte Methoden in alle Repositorys hinzuzufügen.
Dieser Blogbeitrag beschreibt, wie wir benutzerdefinierte Methoden in alle Spring Data JPA-Repositorys einfügen können. Während dieses Blogbeitrags werden wir eine Methode implementieren, die die folgenden Anforderungen erfüllt:

  • Es löscht die Entität, deren ID als Methodenparameter angegeben ist.
  • Es gibt ein Optional zurück die die gelöschte Entität enthält. Wenn keine Entität mit der angegebenen ID gefunden wird, wird ein leeres Optional zurückgegeben .

Fangen wir an.

Erstellen einer Basis-Repository-Schnittstelle

Wenn wir allen Spring Data JPA-Repositories benutzerdefinierte Methoden hinzufügen möchten, müssen wir zunächst eine Basisschnittstelle erstellen, die die benutzerdefinierten Methoden deklariert.

Wir können die Basis-Repository-Schnittstelle erstellen, indem wir diesen Schritten folgen:

  1. Erstellen Sie eine Schnittstelle namens BaseRepository das hat die folgenden Typparameter:
    • Das T type-Parameter ist der Typ der verwalteten Entität.
    • Die ID type-Parameter ist der Typ des Primärschlüssels der verwalteten Entität. Beachten Sie, dass dieser Typparameter Serializable erweitern muss Schnittstelle.
  2. Erweitern Sie das Repository Schnittstelle und geben Sie die erforderlichen Typparameter an.
  3. Kommentieren Sie die erstellte Schnittstelle mit @NoRepositoryBean Anmerkung. Dadurch wird sichergestellt, dass Spring Data JPA nicht versucht, eine Implementierung für das BaseRepository zu erstellen Schnittstelle.
  4. Fügen Sie die deleteById() hinzu -Methode auf die erstellte Schnittstelle. Diese Methode nimmt die ID der gelöschten Entität als Methodenparameter und gibt ein Optional zurück Objekt.

Der Quellcode des BaseRepository Die Benutzeroberfläche sieht wie folgt aus:

import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;

import java.io.Serializable;
import java.util.Optional;

@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends Repository<T, ID> {

    Optional<T> deleteById(ID id);
}

Nachdem wir unsere Basis-Repository-Schnittstelle erstellt haben, müssen wir sie natürlich implementieren. Lassen Sie uns herausfinden, wie wir eine Basis-Repository-Klasse erstellen können, die die angeforderte Entität löscht, indem wir EntityManager verwenden .

Implementierung der Basis-Repository-Schnittstelle

Das SimpleJpaRepository ist die Standardimplementierung von Spring Data JPA-Repository-Schnittstellen. Da wir die von unserer Basis-Repository-Schnittstelle deklarierten Methoden allen Repositories hinzufügen möchten, müssen wir eine benutzerdefinierte Basis-Repository-Klasse erstellen, die das SimpleJpaRepository erweitert Klasse und implementiert das BaseRepository Schnittstelle.

Wir können eine benutzerdefinierte Basis-Repository-Klasse erstellen, indem wir diesen Schritten folgen:

  1. Erstellen Sie ein BaseRepositoryImpl Klasse, die zwei Typparameter hat:
    • Das T type-Parameter ist der Typ der verwalteten Entität.
    • Die ID type-Parameter ist der Typ des Primärschlüssels der verwalteten Entität. Beachten Sie, dass dieser Typparameter Serializable erweitern muss Schnittstelle.
  2. Stellen Sie sicher, dass die BaseRepositoryImpl -Klasse erweitert das SimpleJpaRepository Klasse und implementiert das BaseRepository Schnittstelle. Denken Sie daran, die erforderlichen Typparameter anzugeben.
  3. Fügen Sie einen privaten EntityManager hinzu Feld zur erstellten Klasse und markieren Sie das Feld als final .
  4. Fügen Sie einen Konstruktor hinzu, der zwei Konstruktorargumente akzeptiert:
    1. Eine Klasse Objekt, das die verwaltete Entitätsklasse darstellt.
    2. Ein EntityManager Objekt.
  5. Implementieren Sie den Konstruktor, indem Sie den Konstruktor der Superklasse aufrufen (SimpleJpaRepository ) und Speichern eines Verweises auf den EntityManager Objekt in den privaten EntityManager Feld.
  6. Fügen Sie die deleteById() hinzu -Methode in die erstellte Klasse und implementieren Sie sie, indem Sie die folgenden Schritte ausführen:
    1. Kommentieren Sie die Methode mit @Transactional Anmerkung. Dadurch wird sichergestellt, dass die Methode immer innerhalb einer Lese-Schreib-Transaktion aufgerufen wird.
    2. Suchen Sie das gelöschte Entitätsobjekt, indem Sie die bereitgestellte ID als Suchkriterium verwenden.
    3. Wenn ein Entitätsobjekt gefunden wird, lösche das gefundene Entitätsobjekt und gib ein Optional zurück Objekt, das das gelöschte Entitätsobjekt enthält.
    4. Wenn kein Entitätsobjekt gefunden wird, geben Sie ein leeres Optional zurück Objekt.

Der Quellcode des BaseRepositoryImpl Klasse sieht wie folgt aus:

import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.Optional;

public class BaseRepositoryImpl <T, ID extends Serializable>
        extends SimpleJpaRepository<T, ID>  implements BaseRepository<T, ID> {
		
    private final EntityManager entityManager;

    public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
    }

    @Transactional
    @Override
    public Optional<T> deleteById(ID id) {
        T deleted = entityManager.find(this.getDomainClass(), id);
        Optional<T> returned = Optional.empty();

        if (deleted != null) {
            entityManager.remove(deleted);
            returned = Optional.of(deleted);
        }
        return returned;
    }
}

Nachdem wir unsere Basis-Repository-Klasse erstellt haben, müssen wir eine benutzerdefinierte RepositoryFactoryBean erstellen . Lassen Sie uns herausfinden, wie wir es tun können.

Erstellen einer benutzerdefinierten RepositoryFactoryBean

Die RepositoryFactoryBean ist eine Komponente, die für die Bereitstellung von Implementierungen für Spring Data JPA-Repository-Schnittstellen verantwortlich ist. Da wir die Standardimplementierung (SimpleJpaRepository ) mit unserer benutzerdefinierten Implementierung (BaseRepositoryImpl ), müssen wir eine benutzerdefinierte RepositoryFactoryBean erstellen .

Wir können dies tun, indem wir diesen Schritten folgen:

  1. Erstellen Sie eine BaseRepositoryFactoryBean Klasse, die drei Typparameter hat:
    • Das R type-Parameter ist der Typ des Repositorys. Dieser Typparameter muss das JpaRepository erweitern Schnittstelle.
    • Das T type-Parameter ist der Typ der verwalteten Entität.
    • Das Ich type-Parameter ist der Typ des privaten Schlüssels der Entität. Beachten Sie, dass dieser Typparameter Serializable erweitern muss Schnittstelle.
  2. Erweitern Sie die JpaRepositoryFactoryBean Klasse und geben Sie die erforderlichen Typparameter an.
  3. Fügen Sie eine private statische BaseRepositoryFactory hinzu class auf die erstellte Klasse und erweitern Sie die JpaRepositoryFactory Klasse. Implementieren Sie diese Klasse, indem Sie die folgenden Schritte ausführen:
    1. Fügen Sie der BaseRepositoryFactory zwei Typparameter hinzu Klasse:
      • Das T type-Parameter ist der Typ der verwalteten Entität.
      • Das Ich type-Parameter ist der Typ des privaten Schlüssels der Entität. Beachten Sie, dass dieser Typparameter Serializable erweitern muss Schnittstelle.
    2. Fügen Sie einen privaten abschließenden EntityManager hinzu -Feld in die BaseRepositoryFactory Klasse und markieren Sie das Feld als final
    3. Fügen Sie einen Konstruktor hinzu, der einen EntityManager akzeptiert object als Konstruktorargument und implementieren Sie es, indem Sie die folgenden Schritte ausführen:
      1. Rufen Sie den Konstruktor der Superklasse auf und übergeben Sie den EntityManager Objekt als Konstruktorargument.
      2. Speichern Sie einen Verweis auf den EntityManager Objekt in den privaten EntityManager Feld.
    4. Überschreiben Sie getTargetRepository(RepositoryMetadata metadata) -Methode und implementieren Sie sie, indem Sie ein neues BaseRepositoryImpl zurückgeben Objekt.
    5. Überschreiben Sie die getRepositoryBaseClass(RepositoryMetadata metadata) -Methode und implementieren Sie sie, indem Sie BaseRepositoryImpl.class zurückgeben .
  4. Überschreiben Sie die createRepositoryFactory(EntityManager em) -Methode der JpaRepositoryFactoryBean -Klasse und implementieren Sie sie, indem Sie eine neue BaseRepositoryFactory zurückgeben Objekt.

Der Quellcode der BaseRepositoryFactoryBean Klasse sieht wie folgt aus:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

import javax.persistence.EntityManager;
import java.io.Serializable;

public class BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T,
        I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
        return new BaseRepositoryFactory(em);
    }

    private static class BaseRepositoryFactory<T, I extends Serializable>
            extends JpaRepositoryFactory {

        private final EntityManager em;

        public BaseRepositoryFactory(EntityManager em) {
            super(em);
            this.em = em;
        }

        @Override
        protected Object getTargetRepository(RepositoryMetadata metadata) {
            return new BaseRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), em);
        }

        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }
}

Lassen Sie uns herausfinden, wie wir Spring Data JPA konfigurieren müssen, um unsere benutzerdefinierte RepositoryFactoryBean zu verwenden .

Spring Data JPA konfigurieren

Wir können Spring Data JPA mit einer der folgenden Methoden konfigurieren:

Konfigurieren von Spring Data JPA bei Verwendung von Spring Data JPA <1.9.X

Wenn wir Spring Data JPA <1.9.X verwenden, können wir die Repository-Factory-Bean konfigurieren, indem wir den Wert der repositoryFactoryBeanClass festlegen Attribut von @EnableJpaRepositories Anmerkung.

Der relevante Teil des PersistenceContext Klasse sieht wie folgt aus:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider")
@EnableJpaRepositories(basePackages = {"net.petrikainulainen.springdata.jpa.todo"},
        repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class
)
@EnableTransactionManagement
class PersistenceContext {
	
}

Konfigurieren von Spring Data JPA bei Verwendung von Spring Data JPA 1.9.X oder höher

Wenn wir Spring Data JPA 1.9.X oder neuer verwenden, müssen wir die RepositoryFactoryBean nicht erstellen Klasse. Wir können die Basis-Repository-Klasse einfach konfigurieren, indem wir den Wert der repositoryBaseClass festlegen Attribut von @EnableJpaRepositories Anmerkung.

Der relevante Teil des PersistenceContext Klasse sieht wie folgt aus:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider")
@EnableJpaRepositories(basePackages = {"net.petrikainulainen.springdata.jpa.todo"},
        repositoryBaseClass = BaseRepositoryImpl.class
)
@EnableTransactionManagement
class PersistenceContext {
	
}

Wir können jetzt die neue deleteById() hinzufügen -Methode in unsere Repository-Schnittstellen. Lassen Sie uns herausfinden, wie wir es tun können.

Ändern der eigentlichen Repository-Schnittstellen

Bevor wir unser neues deleteById() verwenden können -Methode müssen wir einige Änderungen an unseren Repository-Schnittstellen vornehmen. Wir können diese Änderungen am TodoRepository vornehmen Schnittstelle, indem Sie diesen Schritten folgen:

  1. Erweitern Sie das BaseRepository Schnittstelle und geben Sie die folgenden Typparameter an:
    • Der Typ der verwalteten Entität ist Todo .
    • Der Typ des privaten Schlüssels der Entität ist Long .
  2. Entfernen Sie das "alte" delete() Methode.

Der Quellcode des TodoRepository Die Benutzeroberfläche sieht wie folgt aus:

import net.petrikainulainen.springdata.jpa.common.BaseRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;


interface TodoRepository extends BaseRepository<Todo, Long> {

    List<Todo> findAll();

    @Query("SELECT t FROM Todo t WHERE " +
            "LOWER(t.title) LIKE LOWER(CONCAT('%',:searchTerm, '%')) OR " +
            "LOWER(t.description) LIKE LOWER(CONCAT('%',:searchTerm, '%')) " +
            "ORDER BY t.title ASC")
    List<Todo> findBySearchTerm(@Param("searchTerm") String searchTerm);

    Optional<Todo> findOne(Long id);

    void flush();

    Todo save(Todo persisted);
}

Das ist es. Wir können jetzt unser neues deleteById() verwenden Methode. Fassen wir zusammen, was wir aus diesem Blogbeitrag gelernt haben.

Zusammenfassung

Dieser Blogbeitrag hat uns drei Dinge gelehrt:

  • Wenn wir allen Repositorys benutzerdefinierte Methoden hinzufügen möchten, müssen wir die Standardimplementierung des Repositorys ersetzen (SimpleJpaRepository ) mit unserer eigenen Repository-Implementierung.
  • Wenn wir Spring Data JPA 1.9.X oder neuer verwenden, müssen wir keine benutzerdefinierte RepositoryFactoryBean erstellen .
  • Unsere Repository-Schnittstellen müssen die Basis-Repository-Schnittstelle erweitern, die die Methoden deklariert, die allen Repositorys hinzugefügt werden.

Der nächste Teil meines Spring Data JPA-Tutorials beschreibt, wie wir Integrationstests für Spring Data JPA-Repositories schreiben können.

P.S. Sie können die Beispielanwendung dieses Blogbeitrags von Github herunterladen.


Java-Tag