[JAVA] Interagir avec une base de données MySQL à l'aide de la fonction ORM (Object-Relational Mapping) d'Apache Cayenne

Dans cet article, nous allons utiliser la fonctionnalité Object Relational Mapping (ORM) de ** Apache Cayenne ** pour travailler avec une base de données ** MySQL ** à partir d'un petit projet ** Java ** construit avec Maven.

Paramètres du projet

Maven est l'un des outils les plus populaires pour créer des applications Java. Dans cette section, vous définirez les dépendances du projet (cela suppose que votre système est vide).

Dans un premier temps, ajoutons les dépendances suivantes pour ajouter Apache Cayenne et le connecteur MYSQL (en particulier le pilote JDBC).

<dependency>
   <groupId>org.apache.cayenne</groupId>
   <artifactId>cayenne-server</artifactId>
   <version>4.0.1</version>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.14</version>
   <scope>runtime</scope>
</dependency>

Le plug-in modeler doit également être défini dans pom.xml. Il s'agit de la commande maven utilisée pour lancer le plug-in Apache Cayenne Modeler à partir de la ligne de commande lorsque vous ouvrez le fichier de mappage pour votre projet actuel.

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

   <configuration>
      <modelFile>${project.basedir}/src/main/resources/cayenne-blog.xml</modelFile>
   </configuration>
</plugin>

Les modélisateurs sont généralement la méthode recommandée pour concevoir et configurer le mappage entre la base de données et la classe de modèle Java réelle.

Vous pouvez le télécharger depuis cette page. Vous devrez télécharger une version conçue pour votre système d'exploitation particulier, ou vous pouvez utiliser la version multiplateforme (JAR) incluse en tant que plug-in Maven à la place. La dernière version stable au moment de la rédaction de cet article est la version [4.1](https://github.com/apache/cayenne/blob/STABLE-4.1/RELEASE-NOTES.txt?spm=a2c65.11461447.0.0.640 c764cCNwoDP & file = RELEASE-NOTES.txt). Cette version nécessite Java 1.8 ou version ultérieure.

Comme étape suivante, construisons le projet avec la commande mvn clean install, démarrons l'interface graphique du modeleur avec la commande mvn cayenne-modeler: run et afficher cet écran.

image.png

Si vous utilisez autre chose que MySQL, vous devrez également modifier le pilote JDBC, de sorte que la configuration dépend de la base de données. Voici une liste complète avec les pilotes correspondants.

Cartographie et conception de bases de données

Par exemple, supposons que vous ayez une base de données existante appelée cayenne_blog qui montre la relation un-à-plusieurs entre deux tables, dans laquelle les paramètres suivants sont définis.

--author: id (PK) et nom --article: id (PK), titre, contenu, author_id (FK) Considérons maintenant une commande SQL qui fait référence à la base de données dans cet exemple.

CREATE TABLE `author` (
  `id` int(11) NOT NULL,
  `name` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Indexes for table `article`
--
ALTER TABLE `article`
  ADD PRIMARY KEY (`id`),
  ADD KEY `author_id` (`author_id`);

--
-- Indexes for table `author`
--
ALTER TABLE `author`
  ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for table `article`
--
ALTER TABLE `article`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

--
-- AUTO_INCREMENT for table `author`
--
ALTER TABLE `author`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

--
-- Constraints for table `article`
--
ALTER TABLE `article`
  ADD CONSTRAINT `article_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`);

db.sql](https://github.com/dassiorleando/apache-cayenne/blob/master/db.sql) Importez le fichier dans phpMyAdmin ou exécutez la commande suivante à partir du serveur MYSQL du terminal Masu: mysql <db.sql.

Maintenant, ajoutons un plugin appelé cayenne-maven-plugin, qui est un paramètre de plugin de modeleur, à pom.xml.

<plugin>
   <groupId>org.apache.cayenne.plugins</groupId>
   <artifactId>cayenne-maven-plugin</artifactId>
   <version>4.0.1</version>

   <configuration>
      <map>${project.basedir}/src/main/resources/blog.map.xml</map>
      <dataSource>
         <driver>com.mysql.jdbc.Driver</driver>
         <url>jdbc:mysql://localhost:3306/cayenne_blog</url>
         <username>root</username>
         <password>root</password>
      </dataSource>
      <dbImport>
         <defaultPackage>com.dassiorleando.apachecayenne.models</defaultPackage>
      </dbImport>
   </configuration>

   <dependencies>
      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>5.1.44</version>
         <scope>runtime</scope>
      </dependency>
   </dependencies>
</plugin>

Ici vous spécifiez où l'ORM enregistre les données (<source de données>) et où le fichier de mappage est enregistré (<map>). À partir de ce paramètre, le nom de la base de données est cayenne_blog, les informations d'identification de la base de données utilisateur sont root: root (mise à jour pour correspondre à celle du serveur MYSQL), et le package par défaut est celui de la structure du projet (créer une classe de modèle). Vous pouvez voir que vous utilisez le package).

Enfin, utilisez la commande cbimport depuis la ligne de commande du projet: mvn cayenne: cdbimport. cdbimport synchronise le fichier de carte XML avec une base de données existante, vous devriez donc obtenir un journal similaire à celui-ci:

INFO] +++ Connecting: SUCCESS.
[INFO] Detected and installed adapter: org.apache.cayenne.dba.mysql.MySQLAdapter
[INFO]   Table: cayenne_blog.AUTO_PK_SUPPORT
[INFO]   Table: cayenne_blog.article
[INFO]   Table: cayenne_blog.author
[INFO]     Db Relationship : toOne  (article.author_id, author.id)
[INFO]     Db Relationship : toMany (author.id, article.author_id)
[INFO] 
[INFO] Map file does not exist. Loaded db model will be saved into '/Users/dassiorleando/projects/opensource/apache-cayenne/src/main/resources/blog.map.xml'
[INFO] 
[INFO] Detected changes: 
[INFO]     Create Table         article
[INFO]     Create Table         author
[INFO]     Create Table         AUTO_PK_SUPPORT
[INFO] 
[WARNING] Can't find ObjEntity for author
[WARNING] Db Relationship (Db Relationship : toOne  (article.author_id, author.id)) will have GUESSED Obj Relationship reflection. 
[INFO] Migration Complete Successfully.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.165 s
[INFO] Finished at: 2019-07-22T17:40:36+01:00
[INFO] Final Memory: 10M/164M
[INFO] ------------------------------------------------------------------------

Générons une classe Java: mvn cayenne: cgen

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building apache-cayenne 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- cayenne-maven-plugin:4.0.1:cgen (default-cli) @ apache-cayenne ---
[INFO] Generating superclass file: /Users/dassiorleando/projects/opensource/apache-cayenne/src/main/java/com/dassiorleando/apachecayenne/model/auto/_Article.java
[INFO] Generating class file: /Users/dassiorleando/projects/opensource/apache-cayenne/src/main/java/com/dassiorleando/apachecayenne/model/Article.java
[INFO] Generating superclass file: /Users/dassiorleando/projects/opensource/apache-cayenne/src/main/java/com/dassiorleando/apachecayenne/model/auto/_Author.java
[INFO] Generating class file: /Users/dassiorleando/projects/opensource/apache-cayenne/src/main/java/com/dassiorleando/apachecayenne/model/Author.java
[INFO] Generating superclass file: /Users/dassiorleando/projects/opensource/apache-cayenne/src/main/java/com/dassiorleando/apachecayenne/model/auto/_AutoPkSupport.java
[INFO] Generating class file: /Users/dassiorleando/projects/opensource/apache-cayenne/src/main/java/com/dassiorleando/apachecayenne/model/AutoPkSupport.java
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Vous devriez immédiatement voir que la structure de votre projet a changé. Nous parlons de _Article.java et _Author.java (les deux sont des extensions de CayenneDataObject). Vous pouvez voir que les mêmes paramètres (au format XML) se trouvent dans le fichier resources / blog.map.xml.

Entrez ensuite la commande mvn cayenne-modeler: run pour démarrer le modeleur. Cliquez sur Nouveau projet et spécifiez le nom du domaine de données (blog) pour le fichier de mappage sur la page suivante. Ici, enregistrez-le dans le même dossier que le fichier de carte créé.

image.png

Cliquez ensuite sur Fichier> Importer la carte de données pour accéder à l'interface utilisateur qui vous permet de créer un lien vers la carte de données.

Une fois que cayenne-blog.xml et blog.map.xml sont liés, le modélisateur peut mettre à jour le modèle pour le refléter dans la classe. Ce sera comme suit.

image.png

Apache Cayenne prend en charge trois stratégies clés principales.

--Cayenne-Generated: Gérer la génération PK. --Génération de base de données: PK est géré par le moteur de base de données. --Séquence personnalisée: vous devez implémenter votre logique personnalisée ici. Dans la capture d'écran suivante, la table author est remplie avec id, un entier auto-incrémenté géré par la base de données.

image.png

Remarque: créez un DataNode qui correspond exactement à la configuration de notre base de données, comme illustré dans la figure suivante.

image.png

Dans le répertoire resources de votre projet Maven, créez un fichier XML spécial appelé cayenne-blog avec le contenu suivant:

<?xml version="1.0" encoding="utf-8"?>
<domain project-version="9">
   <map name="blog"/>

   <node name="datanode"
       factory="org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory"
       schema-update-strategy="org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy">
      <map-ref name="blog"/>
      <data-source>
         <driver value="com.mysql.jdbc.Driver"/>
         <url value="jdbc:mysql://localhost:3306/cayenne_blog"/>
         <connectionPool min="1" max="1"/>
         <login userName="root" password="root"/>
      </data-source>
   </node>
</domain>

Le XMLPoolingDataSourceFactory est responsable du chargement des informations de connexion JDBC à partir de la ressource XML associée au DataNodeDescriptor.

Structure cartographique

Apache Cayenne a sa propre syntaxe pour l'écriture de modèles.

--DataNode (<node>) : modèle de base de données. Il contient toutes les informations nécessaires pour se connecter à la base de données, y compris le nom de la base de données, le pilote et les informations d'identification de l'utilisateur de la base de données. --DataMap (<data-map>) : Un conteneur d'entités persistantes avec lesquelles vous avez une relation. --DbAttribute (<db-attribute>) : Représente une colonne dans une table de base de données. --DbEntity (<db-entity>) : Une seule table de base de données ou modèle de vue. Vous pouvez avoir une relation avec DbAttributes.

--ʻObjEntity () : Un modèle de classe Java persistant unique composé d'ObjAttributes, qui correspond aux propriétés de la classe d'entité, et d'ObjRelationships, qui est une propriété avec le type d'une autre entité. .. --ʻEmbeddable (<embeddable>) : Un modèle de classe Java qui agit comme une propriété d'ObjEntity, mais prend en charge plusieurs colonnes dans la base de données. --procedure (<procedure>): Enregistre la procédure stockée dans la base de données. Utilisé lors de la cartographie.

Pour plus de détails, reportez-vous au [Guide] suivant (https://cayenne.apache.org/docs/3.1/cayenne-guide/#cayenne-mapping-structure?spm=a2c65.11461447.0.0.640c764cCNwoDP).

Application de CRUD au modèle

Dans cette section, nous appliquerons quelques opérations de base aux modèles (ʻArticle et ʻAuthor). «La classe ObjectSelect» a des méthodes statiques qui sont utiles pour interroger la base de données, mais pour les insertions et les mises à jour, elle utilise le contexte du serveur (ObjectContext) qui est utilisé pour valider les changements. est nécessaire.

Voici comment obtenir le contexte du serveur associé à notre projet.

ServerRuntime cayenneRuntime = ServerRuntime.builder()
        .addConfig("cayenne-blog.xml")
        .build();

ObjectContext context = cayenneRuntime.newContext();

Remarque: le fichier cayenne-blog.xml se trouve dans le dossier de ressources de votre projet.

Créer un objet

Vous pouvez créer un objet avec la requête suivante.

/**
 * Save an author
 * @param name
 */
public void save(String name) {
    // Save a single author
    Author author = this.context.newObject(Author.class);
    author.setName(name);

    context.commitChanges();
}

Lire un objet

Vous pouvez charger l'objet avec la requête suivante.

/**
 * Find an author by its ID
 * @param id    the author's ID
 * @return      the matched author or null if not existing
 */
public Author findById(int id) {
    Author author = Cayenne.objectForPK(context, Author.class, id);
    return author;
}

/**
 * Looking for an author by name
 * @param name  the name to look up with
 * @return      the first matched author or null if not existing
 */
public Author findByName(String name) {
    Author foundAuthor = ObjectSelect.query(Author.class)
            .where(Author.NAME.eq(name))
            .selectOne(this.context);

    return foundAuthor;
}

/**
 * Find authors by name starting with(like%)
 * @param partName expected name part
 * @return         list of authors
 */
public List<Author> findByNameLike(String partName) {
    // Let's apply a case-insensitive LIKE on the Author's name column
    // We get all the authors with their name starting with "partName"
    List<Author> authorsLike = ObjectSelect.query(Author.class)
            .where(Author.NAME.likeIgnoreCase(partName + "%"))
            .select(context);

    return authorsLike;
}

/**
 * Find authors by name ending with
 * @param partName expected name part
 * @return         list of authors
 */
public List<Author> findByNameEndWith(String partName) {
    // All authors with names ending with "partName"
    List<Author> authorsEnd = ObjectSelect.query(Author.class)
            .where(Author.NAME.endsWith(partName))
            .select(context);

    return authorsEnd;
}

Trouver tous les enregistrements en classe

Vous pouvez interroger tous les auteurs précédemment enregistrés à l'aide de la requête suivante:

public List<Author> findAll() {
    // Looking for all authors
    List<Author> authors = ObjectSelect
            .query(Author.class)
            .select(this.context);
    return authors;
}

Mettre à jour l'objet

Vous pouvez mettre à jour l'objet avec la requête suivante.

/**
 * Update an author
 * @param id        the author's ID
 * @param newName   the new name to set
 * @return          true for a successful operation and false unknown author
 */
public boolean update(int id, String newName) {
    if (StringUtils.isEmpty(newName)) return false;

    // Get the author to update
    Author author = this.findById(id);

    if (author == null) return false;

    // Set its name
    author.setName(newName);
    context.commitChanges();
    return true;
}

Relation aux objets

Voici comment lier un article écrit par un auteur avec l'auteur.

/**
 * Attach a fake article to the author
 * @param id    the author's ID
 * @return      true for a successful operation and false unknown author
 */
public boolean attachArticle(int id) {
    // Get the author to link with
    Author author = this.findById(id);

    if (author == null) return false;

    // Create a fake article and link it to the current author
    Article article = context.newObject(Article.class);
    article.setTitle("My post title");
    article.setContent("The content");
    article.setAuthor(author);

    context.commitChanges();

    // Get author's linked data (articles)
    List<Article> articles = author.getArticles();

    return true;
}

Supprimer l'objet

Vous pouvez supprimer l'objet avec la requête suivante.

/**
 * Delete an author
 * @param id author's ID
 * @return   true for a successful operation and false unknown author
 */
public boolean delete(int id) {
    // Get the author to delete
    Author author = this.findById(id);

    if (author != null) {
        context.deleteObjects(author);
        context.commitChanges();
        return true;
    } else {
        return false;
    }
}

Supprimer tous les enregistrements de la classe

L'API Apache Cayenne vous permet de supprimer tous les enregistrements d'une table à l'aide de SQLTemplate, mais ici nous fournissons simplement une requête de suppression SQL de base avec la classe cible.

// SQL delete queries for Author and Article classes
SQLTemplate deleteArticles = new SQLTemplate(Article.class, "delete from article");
SQLTemplate deleteAuthors = new SQLTemplate(Author.class, "delete from author");

// Applying the deletion queries
context.performGenericQuery(deleteArticles);
context.performGenericQuery(deleteAuthors);

Expression et Expression Factory

Il existe de nombreuses possibilités pour créer des requêtes avancées à l'aide d'Apache Cayenne. Cependant, dans la plupart des cas, Expression et ExpressionFactory J'utilise la classe, mais voici un exemple Je vais en présenter quelques-uns.

--likeExp: Utilisé pour construire une expression LIKE. --likeIgnoreCaseExp: Utilisé pour construire l'expression LIKE_IGNORE_CASE. --containsExp: une expression utilisée pour les requêtes LIKE qui a un modèle qui correspond à n'importe quel endroit de la chaîne. --containsIgnoreCaseExp: similaire à containsExp, mais avec une approche insensible à la casse. --startsWithExp: Le modèle correspond au début de la chaîne. --startsWithIgnoreCaseExp: Similaire à startsWithExp, mais avec une approche insensible à la casse. --ʻEndsWithExp: une expression qui correspond à la fin de la chaîne. --ʻEndsWithIgnoreCaseExp: une expression qui correspond à la fin d'une chaîne en utilisant une approche insensible à la casse. --ʻExpTrue: Utilisé pour les expressions "True". --ʻExpFalse: Utilisé dans les expressions pour la valeur booléenne "False". --ʻAndExp: Utilisé pour concaténer deux expressions en utilisant l'opérateur ʻand. --ʻOrExp: Utilisé pour concaténer deux expressions en utilisant l'opérateur ʻor.

Conclusion

Dans ce didacticiel, vous avez appris à configurer la fonctionnalité ORM (Object Relational Mapping) d'Apache Cayenne pour une base de données MySQL et les opérations CRUD de base comme exemple de requête avec une relation un-à-plusieurs. Le code source complet de cet article est disponible sur Github.

Recommended Posts

Interagir avec une base de données MySQL à l'aide de la fonction ORM (Object-Relational Mapping) d'Apache Cayenne
Essayez de faire fonctionner la base de données de documents en utilisant X DevAPI avec MySQL Connector / J 8.0.15
Créez une application mémo avec Tomcat + JSP + Servlet + MySQL à l'aide d'Eclipse