Federdaten jpa

In dem Artikel werde ich die Verwendung von Spring Data beschreiben.

Spring Data ist ein zusätzlicher praktischer Mechanismus, um mit Datenbankentitäten zu interagieren, diese in einem Repository zu organisieren, Daten abzurufen und in einigen Fällen zu ändern. In diesem Fall reicht es aus, eine Schnittstelle und Methode darin ohne Implementierung zu deklarieren.

Inhalt:

  1. Frühlings-Repository
  2. Methoden vom Methodennamen anfordern
  3. Konfiguration und Einrichtung
  4. Spezielle Parameterverarbeitung
  5. Benutzerdefinierte Repository-Implementierungen
  6. Benutzerdefiniertes Basis-Repository
  7. Abfragemethoden - Abfrage


1. Spring Repository


Das Grundkonzept in Spring Data ist das Repository. Dies sind mehrere Schnittstellen, die JPA Entity verwenden, um mit ihr zu interagieren. Also zum Beispiel eine Schnittstelle
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID>
bietet grundlegende Operationen zum Suchen, Speichern und Löschen von Daten (CRUD-Operationen)

 T save(T entity); Optional findById(ID primaryKey); void delete(T entity); 

und andere Operationen.

Es gibt andere Abstraktionen, z. B. PagingAndSortingRepository.

Das heißt, Wenn die von der Schnittstelle bereitgestellte Liste ausreicht, um mit der Entität zu interagieren, können Sie die Basisschnittstelle für Ihre Entität direkt erweitern, sie mit Ihren Abfragemethoden ergänzen und Vorgänge ausführen. Jetzt werde ich kurz die Schritte zeigen, die für den einfachsten Fall erforderlich sind (ohne von der Konfiguration, ORM, Datenbank abgelenkt zu werden).

1. Erstellen Sie eine Entität

 @Entity @Table(name = "EMPLOYEES") public class Employees { private Long employeeId; private String firstName; private String lastName; private String email; // . . . 

2. Von einer der Spring Data-Schnittstellen geerbt, z. B. von CrudRepository

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> 

3. Verwenden Sie im Client (Service) eine neue Schnittstelle für Datenoperationen

 @Service public class EmployeesDataService { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Transactional public void testEmployeesCrudRepository() { Optional<Employees> employeesOptional = employeesCrudRepository.findById(127L); //.... } 

Hier habe ich die vorgefertigte findById- Methode verwendet. Das heißt, So schnell und einfach erhalten wir ohne Implementierung eine vorgefertigte Liste der Vorgänge von CrudRepository:

  S save(S var1); Iterable<S> saveAll(Iterable<S> var1); Optional<T> findById(ID var1); boolean existsById(ID var1); Iterable<T> findAll(); Iterable<T> findAllById(Iterable<ID> var1); long count(); void deleteById(ID var1); void delete(T var1); void deleteAll(Iterable<? extends T> var1); void deleteAll(); 

Es ist klar, dass diese Liste höchstwahrscheinlich nicht ausreicht, um mit der Entität zu interagieren, und hier können Sie Ihre Schnittstelle mit zusätzlichen Abfragemethoden erweitern.

2. Fragen Sie Methoden aus dem Methodennamen ab


Anforderungen an die Entität können direkt aus dem Methodennamen erstellt werden. Dazu wird das Find ... By, read ... By, query ... By, count ... By und get ... By-Präfixe verwendet, weiter vom Methodenpräfix entfernt beginnt es, den Rest zu analysieren. Der einleitende Satz kann zusätzliche Ausdrücke enthalten, z. B. Distinct. Als nächstes fungiert das erste By als Trennzeichen, um den Beginn der tatsächlichen Kriterien anzuzeigen. Sie können Bedingungen für Entitätseigenschaften definieren und diese mit And und Or kombinieren. Beispiele

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { //    firstName And LastName Optional<Employees> findByFirstNameAndLastName(String firstName, String lastName); //   5  FirstName       FirstName List<Employees> findFirst5ByFirstNameStartsWithOrderByFirstName(String firstNameStartsWith); 

Die Dokumentation definiert die gesamte Liste und die Regeln zum Schreiben der Methode. Das Ergebnis kann eine Entität T, Optional, List, Stream sein. In einer Entwicklungsumgebung wie Idea gibt es einen Hinweis zum Schreiben von Abfragemethoden.

Bild
Es reicht aus, eine Methode auf diese Weise ohne Implementierung zu definieren, und Spring bereitet eine Anforderung für die Entität vor.

 @SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testFindByFirstNameAndLastName() { Optional<Employees> employeesOptional = employeesCrudRepository.findByFirstNameAndLastName("Alex", "Ivanov"); 

3. Konfiguration und Einrichtung


Das gesamte Projekt ist auf Github verfügbar
github DemoSpringData

Hier werde ich nur auf einige Funktionen eingehen.

TransactionManager-, dataSource- und entityManagerFactory-Beans werden in context.xml definiert. Es ist wichtig anzuzeigen

 <jpa:repositories base-package="com.example.demoSpringData.repositories"/> 

Pfad, in dem Repositorys definiert sind.

EntityManagerFactory ist für die Arbeit mit Hibernate ORM konfiguriert und wiederum mit der Oracle XE-Datenbank. Hier sind andere Optionen möglich. In context.xml ist dies alles sichtbar. Die POM-Datei enthält alle Abhängigkeiten.

4. Spezielle Verarbeitung von Parametern


In Abfragemethoden können Sie in ihren Parametern spezielle Parameter Pageable, Sort sowie Einschränkungen Top und First verwenden.

So können Sie beispielsweise die zweite Seite (Index mit -0) in der Größe von drei Elementen verwenden und nach Vorname sortieren. Nachdem Sie den Parameter Pageable in der Repository-Methode angegeben haben, werden auch die Kriterien aus dem Methodennamen verwendet - „Suche nach Vorname beginnend mit%„

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { List<Employees> findByFirstNameStartsWith(String firstNameStartsWith, Pageable page); //.... } //   @Test @Transactional public void testFindByFirstNameStartsWithOrderByFirstNamePage() { List<Employees> list = employeesCrudRepository .findByFirstNameStartsWith("A", PageRequest.of(1,3, Sort.by("firstName"))); list.forEach(e -> System.out.println(e.getFirstName() + " " +e.getLastName())); } 

5. Benutzerdefinierte Implementierungen für das Repository


Angenommen, Sie benötigen eine Methode im Repository, die nicht durch den Namen der Methode beschrieben werden kann, und können sie dann über Ihre eigene Schnittstelle und ihre Implementierungsklasse implementieren. Im folgenden Beispiel werde ich dem Repository eine Methode hinzufügen, um Mitarbeiter mit maximalem Gehalt zu erhalten.

Schnittstelle deklarieren

 public interface CustomizedEmployees<T> { List<T> getEmployeesMaxSalary(); } 

Implementiert die Schnittstelle. Mit HQL (SQL) bekomme ich Mitarbeiter mit maximaler Bezahlung, andere Implementierungen sind möglich.

 public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Override public List getEmployeesMaxSalary() { return em.createQuery("from Employees where salary = (select max(salary) from Employees )", Employees.class) .getResultList(); } } 

Außerdem können Crud Repository-Mitarbeiter um CustomizedEmployees erweitert werden.

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees> 

Hier gibt es ein wichtiges Merkmal. Die Klasse, die die Schnittstelle implementiert, sollte auf Impl enden (Postfix), oder in der Konfiguration müssen Sie Ihren Postfix einfügen

 <repositories base-package="com.repository" repository-impl-postfix="MyPostfix" /> 

Überprüfen der Funktionsweise dieser Methode über das Repository

 public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testMaxSalaryEmployees() { List<Employees> employees = employeesCrudRepository.getEmployeesMaxSalary(); employees.stream() .forEach(e -> System.out.println(e.getFirstName() + " " + e.getLastName() + " " + e.getSalary())); } 

In einem anderen Fall, in dem das Verhalten einer vorhandenen Methode in der Spring-Schnittstelle geändert werden muss, z. B. Löschen in CrudRepository, muss anstelle des Löschens aus der Datenbank ein Löschzeichen gesetzt werden. Die Technik ist genau die gleiche. Unten ist ein Beispiel:

 public interface CustomizedEmployees<T> { void delete(T entity); // ... } //  CustomizedEmployees public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Transactional @Override public void delete(Object entity) { Employees employees = (Employees) entity; employees.setDeleted(true); em.persist(employees); } 

Wenn Sie jetzt delete in employeeCrudRepository aufrufen, wird das Objekt nur als gelöscht markiert.

6. User Base Repository


Im vorherigen Beispiel habe ich gezeigt, wie das Lösch-Repository einer Entität in Crud neu definiert wird. Wenn Sie dies jedoch für alle Projekt-Entitäten tun müssen, müssen Sie Ihre eigene Schnittstelle nicht für jede Entität so gut machen. In Spring-Daten können Sie Ihr Basis-Repository konfigurieren. Dafür:
Eine Schnittstelle ist deklariert und darin eine Methode zum Überschreiben (oder allen Projekteinheiten gemeinsam). Hier habe ich für alle meine Entitäten meine BaseEntity- Schnittstelle eingeführt (dies ist nicht erforderlich). Um das Aufrufen allgemeiner Methoden zu vereinfachen , stimmen ihre Methoden mit den Methoden der Entität überein.

 public interface BaseEntity { Boolean getDeleted(); void setDeleted(Boolean deleted); } //  Employees @Entity @Table(name = "EMPLOYEES") public class Employees implements BaseEntity { private Boolean deleted; @Override public Boolean getDeleted() { return deleted; } @Override public void setDeleted(Boolean deleted) { this.deleted = deleted; } //    @NoRepositoryBean public interface BaseRepository <T extends BaseEntity, ID extends Serializable> extends JpaRepository<T, ID> { void delete(T entity); } //    BaseRepository public class BaseRepositoryImpl <T extends BaseEntity, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> { private final EntityManager entityManager; public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); this.entityManager = entityManager; } @Transactional @Override public void delete(BaseEntity entity) { entity.setDeleted(true); entityManager.persist(entity); } } 

In der Konfiguration müssen Sie dieses Basis-Repository angeben. Es ist allen Projekt-Repositorys gemeinsam

  <jpa:repositories base-package="com.example.demoSpringData.repositories" base-class="com.example.demoSpringData.BaseRepositoryImpl"/> 

Jetzt muss das Employees Repository (und andere) aus BaseRepository erweitert werden und es bereits im Client verwenden.

 public interface EmployeesBaseRepository extends BaseRepository <Employees, Long> { // ... } 

Überprüfen von EmployeesBaseRepository

 public class DemoSpringDataApplicationTests { @Resource private EmployeesBaseRepository employeesBaseRepository; @Test @Transactional @Commit public void testBaseRepository() { Employees employees = new Employees(); employees.setLastName("Ivanov"); // Query by Example (QBE) Example<Employees> example = Example.of(employees); Optional<Employees> employeesOptional = employeesBaseRepository.findOne(example); employeesOptional.ifPresent(employeesBaseRepository::delete); } 

Nach wie vor wird das Objekt als gelöscht markiert. Dies wird für alle Entitäten durchgeführt, die die BaseRepository-Schnittstelle erweitern. Im Beispiel wurde die Suchmethode - Query by Example (QBE) angewendet. Ich werde sie hier nicht beschreiben. Das Beispiel zeigt, was sie tut, einfach und bequem.

7. Abfragemethoden - Abfrage


Zuvor habe ich geschrieben, dass, wenn Sie eine bestimmte Methode oder deren Implementierung benötigen, die nicht mit dem Methodennamen beschrieben werden kann, dies über eine benutzerdefinierte Schnittstelle (CustomizedEmployees) erfolgen und eine Berechnungsimplementierung durchführen kann. Sie können auch in die andere Richtung gehen, indem Sie die Abfrage (HQL oder SQL) angeben, wie diese Funktion berechnet werden soll.
In meinem Beispiel mit getEmployeesMaxSalary ist diese Implementierungsoption noch einfacher. Ich werde es mit dem Gehaltseingabeparameter komplizieren. Das heißt, Es reicht aus, die Berechnungsmethode und die Anforderung in der Schnittstelle zu deklarieren.

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees> { @Query("select e from Employees e where e.salary > :salary") List<Employees> findEmployeesWithMoreThanSalary(@Param("salary") Long salary, Sort sort); // ... } 

Überprüfen

 @Test @Transactional public void testFindEmployeesWithMoreThanSalary() { List<Employees> employees = employeesCrudRepository.findEmployeesWithMoreThanSalary(10000L, Sort.by("lastName")); 

Ich möchte nur erwähnen, dass es Änderungsanforderungen geben kann. Dazu wird ihnen eine zusätzliche @ Modifying- Anmerkung hinzugefügt

 @Modifying @Query("update Employees e set e.firstName = ?1 where e.employeeId = ?2") int setFirstnameFor(String firstName, String employeeId); 

Eine weitere großartige Funktion von Abfrageanmerkungen ist das Ersetzen des Entitätsdomänentyps in die Abfrage mithilfe der Vorlage # {# entityName} über SpEL-Ausdrücke.

Wenn ich beispielsweise in meinem hypothetischen Beispiel das Zeichen "gelöscht" für alle Entitäten haben muss, erstelle ich eine grundlegende Schnittstelle mit einer Methode zum Abrufen einer Liste von Objekten mit dem Zeichen "gelöscht" oder "aktiv".

 @NoRepositoryBean public interface ParentEntityRepository<T> extends Repository<T, Long> { @Query("select t from #{#entityName} t where t.deleted = ?1") List<T> findMarked(Boolean deleted); } 

Darüber hinaus können alle Repositorys für Entitäten erweitert werden. Annotieren Sie @NoRepositoryBean mit Schnittstellen, die keine Repositorys sind, sich jedoch im Konfigurationsordner "Basispaket" befinden.

Mitarbeiter-Repository

 @Repository public interface EmployeesEntityRepository extends ParentEntityRepository <Employees> { } 

Wenn die Anforderung ausgeführt wird, wird der Entitätsname T in den Anforderungshauptteil für ein bestimmtes Repository eingesetzt, das das ParentEntityRepository erweitert, in diesem Fall Employees.

Überprüfen Sie

 @SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private EmployeesEntityRepository employeesEntityRepository; @Test @Transactional public void testEntityName() { List<Employees> employeesMarked = employeesEntityRepository.findMarked(true); // ... 

Material
Spring Data JPA - Referenzdokumentation
Projekt auf Github .

Source: https://habr.com/ru/post/de435114/


All Articles