Eine Anleitung zum DeltaSpike-Datenmodul

Eine Anleitung zum DeltaSpike-Datenmodul

1. Überblick

Apache DeltaSpike ist ein Projekt, dascollection of CDI extensions für Java-Projekte bereitstellt. Für die Laufzeit muss eine CDI-Implementierung verfügbar sein.

Of course, it can work with the different implementation of CDI - JBoss Weld oder OpenWebBeans. Es wurde auch auf vielen Anwendungsservern getestet.

In diesem Tutorial konzentrieren wir uns aufone of the best known and useful – Data module.

2. Einrichtung des DeltaSpike-Datenmoduls

Das Apache DeltaSpike-Datenmodul wird fürsimplify implementation of the repository pattern verwendet. Es erlaubtreducing a boilerplate code by providing centralized logic for queries creation and execution.

Es ist demSpring Data-Projekt sehr ähnlich. Um eine Datenbank abzufragen, müssen wir eine Methodendeklaration (ohne Implementierung) definieren, die der definierten Namenskonvention folgt oder die die Annotation@Queryenthält. Die Implementierung erfolgt für uns über die CDI-Erweiterung.

In den nächsten Unterabschnitten erfahren Sie, wie Sie das Apache DeltaSpike Data-Modul in unserer Anwendung einrichten.

2.1. Erforderliche Abhängigkeiten

Um das Apache DeltaSpike Data-Modul in der Anwendung zu verwenden, müssen die erforderlichen Abhängigkeiten eingerichtet werden.

Wenn Maven unser Build-Tool ist, müssen wir Folgendes verwenden:


    org.apache.deltaspike.modules
    deltaspike-data-module-api
    1.8.2
    compile


    org.apache.deltaspike.modules
    deltaspike-data-module-impl
    1.8.2
    runtime

Wenn wir Gradle verwenden:

runtime 'org.apache.deltaspike.modules:deltaspike-data-module-impl'
compile 'org.apache.deltaspike.modules:deltaspike-data-module-api'

Artefakte des Apache DeltaSpike Data-Moduls sind in Maven Central verfügbar:

Zurun an application with Data module, we also need a JPA and CDI implementations available at runtime.

Obwohl es möglich ist, Apache DeltaSpike in einer Java SE-Anwendung auszuführen, wird es in den meisten Fällen auf dem Anwendungsserver (z. B. Wildfly oder WebSphere) bereitgestellt.

Anwendungsserver bieten vollständige Java EE-Unterstützung, sodass wir nichts weiter tun müssen. Im Fall einer Java SE-Anwendung müssen diese Implementierungen bereitgestellt werden (z. B. durch Hinzufügen von Abhängigkeiten zum Ruhezustand und zu JBoss Weld).

Als Nächstes behandeln wir auch die erforderliche Konfiguration fürEntityManager.

2.2. Entity Manager-Konfiguration

DieData module requires EntityManager to be injected over CDI.

Wir können dies erreichen, indem wir einen CDI-Produzenten einsetzen:

public class EntityManagerProducer {

    @PersistenceContext(unitName = "primary")
    private EntityManager entityManager;

    @ApplicationScoped
    @Produces
    public EntityManager getEntityManager() {
        return entityManager;
    }
}

Der obige Code setzt voraus, dass wir eine Persistenzeinheit mit dem Namenprimary haben, der in der Dateipersistence.xml definiert ist.

Im Folgenden sehen Sie ein Beispiel für die Definition:


   java:jboss/datasources/example-jee7-seedDS
   
      
      
   

Die Persistenz-Einheit in unserem Beispiel verwendet den Transaktionstyp JTA. Dies bedeutet, dass wir eine Transaktionsstrategie bereitstellen müssen, die wir verwenden werden.

2.3. Transaktionsstrategie

In case we’re using JTA transaction type for our data source then we have to define Transaction Strategy that will be used in the Apache DeltaSpike repositories. Wir können es in der Datei vonapache-deltaspike.propertiestun (unter dem Verzeichnis vonMETA-INF):

globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy=org.apache.deltaspike.jpa.impl.transaction.ContainerManagedTransactionStrategy

Es gibt vier Arten von Transaktionsstrategien, die wir definieren können:

  • BeanManagedUserTransactionStrategy

  • ResourceLocalTransactionStrategy

  • ContainerManagedTransactionStrategy

  • EnvironmentAwareTransactionStrategy

Alle implementierenorg.apache.deltaspike.jpa.spi.transaction.TransactionStrategy.

Dies war der letzte Teil der Konfiguration, die für unser Datenmodul erforderlich war.

Als Nächstes zeigen wir, wie die Repository-Musterklassen implementiert werden.

3. Repository-Klassen

Wenn wir die Klasseany abstract class or interface can become a repositorydes Apache DeltaSpike-Datenmoduls verwenden.

All we have to do is toadd an @Repositoryannotation mit einemforEntity-Attribut, das die JPA-Entität definiert, die unser Repository verarbeiten soll:

@Entity
public class User {
    // ...
}

@Repository(forEntity = User.class)
public interface SimpleUserRepository {
    // ...
}

oder mit einer abstrakten Klasse:

@Repository(forEntity = User.class)
public abstract class SimpleUserRepository {
    // ...
}

Das Datenmodul erkennt Klassen (oder Schnittstellen) mit einer solchen Anmerkung und verarbeitet darin enthaltene Methoden.

Es gibt nur wenige Möglichkeiten, die auszuführende Abfrage zu definieren. In den folgenden Abschnitten werden wir in Kürze nacheinander darauf eingehen.

4. Abfrage vom Methodennamen

Die erste Möglichkeit zudefine a query is to use method name which follows a defined naming convention.

Es sieht so aus:

(Entity|Optional|List|Stream) (prefix)(Property[Comparator]){Operator Property [Comparator]}

Als nächstes konzentrieren wir uns auf jeden Teil dieser Definition.

4.1. Rückgabetyp

Diereturn type mainly defines how many objects our query might return. Wir können einen einzelnen Entitätstyp nicht als Rückgabewert definieren, wenn unsere Abfrage möglicherweise mehr als ein Ergebnis zurückgibt.

Die folgende Methode löst eine Ausnahme aus, wenn mehr als einUser mit dem angegebenen Namen vorhanden sind:

public abstract User findByFirstName(String firstName);

Das Gegenteil ist nicht der Fall - wir können einen Rückgabewert alsCollection definieren, obwohl das Ergebnis nur eine einzelne Entität ist.

public abstract Collection findAnyByFirstName(String firstName);

Das Methodennamenpräfix, das einen Wert als Rückgabetyp vorschlägt (z. B.findAny), wird unterdrückt, wenn wir den Rückgabewert alsCollection definieren.

Die obige Abfrage gibt alleUsers mit einem Vornamen zurück, der mit dem Präfix des Methodennamens übereinstimmt, was auf etwas anderes hindeutet.

Solche Kombinationen (CollectionRückgabetyp und ein Präfix, das eine Rückgabe mit einem einzigen Wert vorschlägt) sollten vermieden werden, da der Code nicht intuitiv und schwer verständlich wird.

Der nächste Abschnitt enthält weitere Details zum Präfix des Methodennamens.

4.2. Präfix für Abfragemethode

Prefix defines the action we want to execute on the repository. Am nützlichsten ist es, Entitäten zu finden, die bestimmten Suchkriterien entsprechen.

Es gibt viele Präfixe für diese Aktion wiefindBy,findAny,findAll. . Die detaillierte Liste finden Sie in den offiziellen Apache DeltaSpikedocumentation:

public abstract User findAnyByLastName(String lastName);

Es gibt jedoch auchother method templates which are used for counting and removing entities. Wir könnencount alle Zeilen in einer Tabelle:

public abstract int count();

Außerdem existiert die Methodenvorlage vonremove, die wir in unser Repository aufnehmen können:

public abstract void remove(User user);

Die Unterstützung für die MethodenpräfixecountBy undremoveBy wird in der nächsten Version von Apache DeltaSpike 1.9.0 hinzugefügt.

Der nächste Abschnitt zeigt, wie wir den Abfragen weitere Attribute hinzufügen können.

4.3. Abfrage mit vielen Eigenschaften

In der Abfrage können wirmany properties combined with and operators verwenden.

public abstract Collection findByFirstNameAndLastName(
  String firstName, String lastName);
public abstract Collection findByFirstNameOrLastName(
  String firstName, String lastName);

Wir können so viele Eigenschaften kombinieren, wie wir wollen. Es ist auch die Suche nach verschachtelten Eigenschaften verfügbar, die wir als Nächstes anzeigen.

4.4. Abfrage mit verschachtelten Eigenschaften

Diequery can also use nested properties.

Im folgenden Beispiel hat die EntitätUsereine Adresseneigenschaft vom TypAddress und die EntitätAddresseine Eigenschaftcity:

@Entity
public class Address {
private String city;
    // ...
}
@Entity
public class User {
    @OneToOne
    private Address address;
    // ...
}
public abstract Collection findByAddress_city(String city);

4.5. Bestellung in der Abfrage

DeltaSpike erlaubt unsdefine an order in which result should be returned. Wir können sowohl aufsteigende als auch absteigende Reihenfolge definieren:

public abstract List findAllOrderByFirstNameAsc();

Wie oben gezeigt,we have to do is to add a part to the method name which contains property name we want to sort by and the short name for the order direction.

Wir können viele Aufträge leicht kombinieren:

public abstract List findAllOrderByFirstNameAscLastNameDesc();

Als Nächstes zeigen wir, wie Sie die Größe des Abfrageergebnisses begrenzen können.

4.6. Beschränken Sie die Größe und Paginierung des Abfrageergebnisses

Es gibt Anwendungsfälle, in denen wir einige erste Zeilen aus dem gesamten Ergebnis abrufen möchten. Dies ist das sogenannte Abfragelimit. Mit dem Datenmodul ist dies auch unkompliziert:

public abstract Collection findTop2OrderByFirstNameAsc();
public abstract Collection findFirst2OrderByFirstNameAsc();

First undtop können austauschbar verwendet werden.

Wir können dannenable query pagination by providing two additional parameters: @FirstResult and @MaxResult:

public abstract Collection findAllOrderByFirstNameAsc(@FirstResult int start, @MaxResults int size);

Wir haben bereits viele Methoden im Repository definiert. Einige von ihnen sind generisch und sollten einmal definiert und von jedem Repository verwendet werden.

Apache DeltaSpike bietet einige grundlegende Typen, mit denen wir eine Vielzahl von Methoden verwenden können.

Im nächsten Abschnitt werden wir uns darauf konzentrieren, wie das geht.

5. Grundlegende Repository-Typen

Zuget some basic repository methods, our repository should extend basic type provided by Apache DeltaSpike. Es gibt einige davon wieEntityRepository,FullEntityRepository, usw.:

@Repository
public interface UserRepository
  extends FullEntityRepository {
    // ...
}

Oder mit einer abstrakten Klasse:

@Repository
public abstract class UserRepository extends AbstractEntityRepository {
    // ...
}

Die obige Implementierung gibt uns eine Menge Methoden, ohne zusätzliche Codezeilen zu schreiben. Wir haben also das gewonnen, was wir wollten - wir reduzieren den Code für Boilerplates massiv.

Wenn wir den Basis-Repository-Typ verwenden, muss kein zusätzlicherforEntity-Attributwert an unsere@Repository-Anmerkung. übergeben werden

Wenn wir abstrakte Klassen anstelle von Schnittstellen für unsere Repositorys verwenden, erhalten wir eine zusätzliche Möglichkeit, eine benutzerdefinierte Abfrage zu erstellen.

Abstract base repository classes, e.g., AbstractEntityRepository gives us an access to fields (via getters) or utility methods which we can use to create a query:

public List findByFirstName(String firstName) {
    return typedQuery("select u from User u where u.firstName = ?1")
      .setParameter(1, firstName)
      .getResultList();
}

Im obigen Beispiel haben wir die DienstprogrammmethodetypedQueryverwendet, um eine benutzerdefinierte Implementierung zu erstellen.

Die letzte Möglichkeit, eine Abfrage zu erstellen, besteht darin, die Annotation von@Queryzu verwenden, die als Nächstes angezeigt wird.

6. @Query Anmerkung

Die SQLquery to execute can also be defined with the @Query annotation. Es ist der Spring-Lösung sehr ähnlich. Wir müssen der Methode eine Anmerkung mit SQL-Abfrage als Wert hinzufügen.

Standardmäßig ist dies eine JPQL-Abfrage:

@Query("select u from User u where u.firstName = ?1")
public abstract Collection findUsersWithFirstName(String firstName);

Wie im obigen Beispiel können wir Parameter einfach über einen Index an die Abfrage übergeben.

Wenn wir eine Abfrage über natives SQL anstelle von JPQL übergeben möchten, müssen wir ein zusätzliches Abfrageattribut definieren -isNative mit dem wahren Wert:

@Query(value = "select * from User where firstName = ?1", isNative = true)
public abstract Collection findUsersWithFirstNameNative(String firstName);

7. Fazit

In diesem Artikel haben wir die grundlegende Definition von Apache DeltaSpike behandelt und uns auf den aufregenden Teil - das Datenmodul - konzentriert. Es ist dem Spring Data Project sehr ähnlich.

Wir haben untersucht, wie das Repository-Muster implementiert wird. Außerdem haben wir drei Möglichkeiten eingeführt, wie Sie eine auszuführende Abfrage definieren.

Wie immer sind die vollständigen Codebeispiele in diesem Artikel inover on Github verfügbar.