Einführung in Apache Cayenne ORM

1. Überblick

Apache Cayenne ist eine Open-Source-Bibliothek, die unter der Apache-Lizenz vertrieben wird und Funktionen wie ein Modellierungswerkzeug, objektrelationales Mapping (ORM) für lokale Persistenzoperationen und Remoting-Dienste bietet.

In den folgenden Abschnitten erfahren Sie, wie Sie mit Apache Cayenne ORM mit einer MySQL-Datenbank interagieren.

2. Abhängigkeiten von Maven

Um zu beginnen, müssen wir nur die folgenden Abhängigkeiten hinzufügen, um Apache Cayenne und MySQL Connector mit dem JDBC-Treiber zusammenzuschalten, um auf unsere Datenbank intro cayenne__ zuzugreifen:

<dependency>
    <groupId>org.apache.cayenne</groupId>
    <artifactId>cayenne-server</artifactId>
    <version>4.0.M5</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
    <scope>runtime</scope>
</dependency>

Lassen Sie uns das Cayenne Modeler-Plugin konfigurieren, das zum Entwerfen oder Festlegen unserer Zuordnungsdatei verwendet wird, die als Brücke zwischen dem Datenbankschema und dem Java-Objekt dient:

<plugin>
    <groupId>org.apache.cayenne.plugins</groupId>
    <artifactId>maven-cayenne-modeler-plugin</artifactId>
    <version>4.0.M5</version>
</plugin>

Anstatt XML-Zuordnungsdateien manuell zu erstellen (selten erstellt), wird empfohlen, den Modeler zu verwenden, ein ziemlich fortgeschrittenes Werkzeug, das in der Cayenne-Distribution enthalten ist.

Sie können sie je nach Betriebssystem von dieser archive herunterladen oder verwenden Sie einfach die Cross-Platform-Version (JAR), die oben als Maven-Plugin enthalten ist.

Das Maven Central-Repository hostet die neuesten Versionen von https://search.maven.org/classic/ search%7Cga%7C1%7Ca%3A%22cayenne-server%22[Apache Cayenne], https://search.maven . org/classic/ search% 7Cga% 7C1% 7Ca% 3A% 22cayenne-modeler-maven-plugin% 22[sein modeler]und https://search.maven.org/classic/#search%7Cgav%7C1%7Cg % 3A% 22mysql% 22% 20AND% 20a% 3A% 22mysql-Connector-java% 22[MySQL-Connector].

Als Nächstes erstellen wir unser Projekt mit mvn install und starten die Modeler-GUI mit dem Befehl mvn cayenne-modeler: run , um als Ausgabe diesen Bildschirm anzuzeigen:

3. Konfiguration

Damit Apache Cayenne die richtige lokale Datenbank nachschlagen kann, müssen Sie nur die entsprechende Treiberdatei, die richtige URL und einen Benutzer in der Datei cayenne-project.xml im Verzeichnis resources angeben:

<?xml version="1.0" encoding="utf-8"?>
<domain project-version="9">
    <node name="datanode"
          factory
      ="org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory"
          schema-update-strategy
      ="org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy">
        <data-source>
            <driver value="com.mysql.jdbc.Driver"/>
            <url value
              ="jdbc:mysql://localhost:3306/intro__cayenne;create=true"/>
            <connectionPool min="1" max="1"/>
            <login userName="root" password="root"/>
        </data-source>
    </node>
</domain>

Hier können wir das sehen:

  • Die lokale Datenbank heißt intro cayenne__

  • Wenn es noch nicht erstellt wurde, erledigt Cayenne dies für uns

  • Wir verbinden uns mit dem Benutzernamen root und dem Passwort root (ändern Sie es

entsprechend den Benutzern, die in Ihrem Datenbankverwaltungssystem registriert sind)

Intern ist es die XMLPoolingDataSourceFactory , die für das Laden von JDBC-Verbindungsinformationen aus einer XML-Ressource verantwortlich ist, die dem DataNodeDescriptor zugeordnet ist.

Beachten Sie, dass diese Parameter relativ zum Datenbankverwaltungssystem und einem JDBC-Treiber sind, da diese Bibliothek viele verschiedene Datenbanken unterstützen kann.

Jeder von ihnen hat einen Adapter in dieser ausführlichen https://cayenne.apache.org/docs/3.0/database-support.html (liste). Beachten Sie, dass die vollständige Dokumentation für Version 4.0 noch nicht verfügbar ist. Wir verweisen hier auf die Vorgängerversion.

** 4. Kartierung

4.1. Modellieren

Klicken Sie nun auf „Projekt öffnen“ , navigieren Sie zum Ressourcenordner des Projekts und wählen Sie die Datei __cayenne-project.xml aus.

Hier haben wir die Wahl, entweder unsere Mapping-Struktur aus einer bestehenden Datenbank zu erstellen oder manuell fortzufahren.

Werfen wir einen Blick auf unsere intro cayenne -Datenbank, die über zwei Tabellen hinweg eine one-to-many__-Beziehung hat, da ein Autor viele Artikel veröffentlichen oder besitzen kann:

  • author: id (PK) und name

  • article: id (PK), title, content und author id (FK) __

Gehen wir nun zu „ Tools> Reengineer Database Schema “ und wir werden alle unsere Mapping-Konfigurationen automatisch füllen. Füllen Sie in der Eingabeaufforderung einfach die dort verfügbare Datenquellenkonfiguration in der Datei cayenne-project.xml aus und klicken Sie auf Weiter:

Auf dem nächsten Bildschirm müssen wir wie folgt "Java-Grundtypen verwenden" aktivieren:

Wir müssen auch sicherstellen, dass com.baeldung.apachecayenne.persistent als Java-Paket abgelegt und gespeichert wird. Wir werden feststellen, dass die XML-Konfigurationsdatei für ihre Eigenschaft defaultPackage entsprechend dem Java-Paket aktualisiert wurde:

In jedem ObjEntity müssen wir das Paket für Unterklassen angeben, wie in der folgenden Abbildung gezeigt, und erneut auf das Symbol "save" klicken:

Wählen Sie nun im Menü "Extras> Klassen generieren" als Typ " Standard Persistent Objects ". und überprüfen Sie auf der Registerkarte __ “Klassen” alle Klassen und klicken Sie auf “Generate”.

Gehen wir zurück zum Quellcode, um zu sehen, dass unsere persistenten Objekte erfolgreich generiert wurden, und sprechen über Article.java und __Author.java .

Alle diese Konfigurationen werden in der Datei datamap.map.xml gespeichert, die sich auch im Ordner resources befindet.

4.2. Mapping-Struktur

Die generierte XML-Zuordnungsdatei im Ressourcenordner verwendet einige eindeutige Tags in Bezug auf Apache Cayenne:

  • DataNode (<node>) - das Modell der Datenbank, alle Inhalte

Informationen, die erforderlich sind, um eine Verbindung zu einer Datenbank herzustellen (Name der Datenbank) Datenbank, den Treiber und die Benutzeranmeldeinformationen) ** DataMap (<data-map>) - es ist ein Container von persistenten Entitäten mit

ihre Beziehungen ** DbAttribute (<db-attribute>) - repräsentiert eine Spalte in einer Datenbank

Tabelle ** DbEntity (<db-entity>) - das Modell einer einzelnen Datenbanktabelle oder

Ansicht, kann es DbAttributes und Beziehungen haben ** ObjEntity (<obj-entity>) - das Modell eines einzelnen persistenten Java

Klasse; aus ObjAttributes, die den Eigenschaften der Entitätsklasse entsprechen und ObjRelationships, Eigenschaften, die einen anderen Typ haben Entität ** Embeddable (<embeddable>) - das Modell einer Java-Klasse, die als

Eigenschaft eines ObjEntity, entspricht aber mehreren Spalten in der Datenbank ** Procedure (<Prozedur>) - um die gespeicherte Prozedur im zu registrieren

Datenbank ** Query (<query>) - Das Modell einer Abfrage, das zur Zuordnung der Abfrage verwendet wird

Konfigurationsdatei ohne zu vergessen, dass wir es auch im Code tun können

5. Cayenne-API

Der einzige verbleibende Schritt ist die Verwendung der Cayenne-API, um unsere Datenbankvorgänge mit generierten Klassen auszuführen. Dabei ist zu wissen, dass die Unterklassen unserer persistenten Klassen nur eine bewährte Methode sind, um das Modell später anzupassen.

5.1. Objekt erstellen

Hier speichern wir nur ein Author -Objekt und prüfen später, ob es nur einen Datensatz dieses Typs in der Datenbank gibt:

@Test
public void whenInsert__thenWeGetOneRecordInTheDatabase() {
    Author author = context.newObject(Author.class);
    author.setName("Paul");

    context.commitChanges();

    long records = ObjectSelect.dataRowQuery(Author.class)
      .selectCount(context);

    assertEquals(1, records);
}

5.2. Ein Objekt lesen

Nachdem wir einen Author gespeichert haben, wählen wir ihn unter anderem durch eine einfache Abfrage einer bestimmten Eigenschaft aus:

@Test
public void whenInsert__andQueryByFirstName__thenWeGetTheAuthor() {
    Author author = context.newObject(Author.class);
    author.setName("Paul");

    context.commitChanges();

    Author expectedAuthor = ObjectSelect.query(Author.class)
      .where(Author.NAME.eq("Paul"))
      .selectOne(context);

    assertEquals("Paul", expectedAuthor.getName());
}

5.3. Alle Datensätze einer Klasse abrufen

Wir werden zwei Autoren speichern und eine Sammlung von Autorenobjekten abrufen, um zu prüfen, ob nur diese beiden gespeichert sind:

@Test
public void whenInsert__andQueryAll__thenWeGetTwoAuthors() {
    Author firstAuthor = context.newObject(Author.class);
    firstAuthor.setName("Paul");

    Author secondAuthor = context.newObject(Author.class);
    secondAuthor.setName("Ludovic");

    context.commitChanges();

    List<Author> authors = ObjectSelect
      .query(Author.class)
      .select(context);

    assertEquals(2, authors.size());
}

5.4. Objekt aktualisieren

Der Aktualisierungsprozess ist auch einfach, aber wir müssen zuerst das gewünschte Objekt haben, bevor Sie seine Eigenschaften ändern und auf die Datenbank anwenden können:

@Test
public void whenUpdating__thenWeGetAnUpatedeAuthor() {
    Author author = context.newObject(Author.class);
    author.setName("Paul");
    context.commitChanges();

    Author expectedAuthor = ObjectSelect.query(Author.class)
      .where(Author.NAME.eq("Paul"))
      .selectOne(context);
    expectedAuthor.setName("Garcia");
    context.commitChanges();

    assertEquals(author.getName(), expectedAuthor.getName());
}

5.5. Anhängen eines Objekts

Wir können einen Artikel einem Autor zuordnen:

@Test
public void whenAttachingToArticle__thenTheRelationIsMade() {
    Author author = context.newObject(Author.class);
    author.setName("Paul");

    Article article = context.newObject(Article.class);
    article.setTitle("My post title");
    article.setContent("The content");
    article.setAuthor(author);

    context.commitChanges();

    Author expectedAuthor = ObjectSelect.query(Author.class)
      .where(Author.NAME.eq("Smith"))
      .selectOne(context);

    Article expectedArticle = (expectedAuthor.getArticles()).get(0);

    assertEquals(article.getTitle(), expectedArticle.getTitle());
}

5.6. Objekt löschen

Durch das Löschen eines gespeicherten Objekts wird dieses vollständig aus der Datenbank entfernt. Danach wird null als Ergebnis der Abfrage angezeigt:

@Test
public void whenDeleting__thenWeLostHisDetails() {
    Author author = context.newObject(Author.class);
    author.setName("Paul");
    context.commitChanges();

    Author savedAuthor = ObjectSelect.query(Author.class)
      .where(Author.NAME.eq("Paul"))
      .selectOne(context);
    if(savedAuthor != null) {
        context.deleteObjects(author);
        context.commitChanges();
    }

    Author expectedAuthor = ObjectSelect.query(Author.class)
      .where(Author.NAME.eq("Paul"))
      .selectOne(context);

    assertNull(expectedAuthor);
}

5.7. Alle Datensätze einer Klasse löschen

Es ist auch möglich, alle Datensätze einer Tabelle mit SQLTemplate __ zu löschen. Hier tun wir dies nach jeder Testmethode, um immer eine leere Datenbank zu haben, bevor jeder Test gestartet wird

@After
public void deleteAllRecords() {
    SQLTemplate deleteArticles = new SQLTemplate(
      Article.class, "delete from article");
    SQLTemplate deleteAuthors = new SQLTemplate(
      Author.class, "delete from author");

    context.performGenericQuery(deleteArticles);
    context.performGenericQuery(deleteAuthors);
}

6. Fazit

In diesem Tutorial konzentrierten wir uns auf die Verwendung von Apache Cayenne ORM, um auf einfache Weise zu demonstrieren, wie CRUD-Operationen mit einer one-to-many -Beziehung ausgeführt werden.

Den Quellcode für diesen Artikel finden Sie wie immer unter over auf GitHub .