[JAVA] [MyBatis] Je souhaite mapper une requête de requête à une table qui a une relation un-à-plusieurs avec un bean imbriqué.

problème

Prenons comme exemples les systèmes de suivi des bogues comme JIRA et Redmine. Ce système crée un projet pour chaque thème. Supposons qu'un ticket soit créé pour chaque projet et que les utilisateurs puissent commenter le ticket. Le diagramme ER est le suivant.

image.png

Pour les données, supposons que cela ressemble à ceci:

image.png

Pensez maintenant à obtenir tout le projet et les commentaires de ticket qui lui sont associés. Il est facile d'écrire une requête, mais que se passe-t-il si vous mappez les résultats à un bean Java imbriqué appelé Project.java? En d'autres termes, une requête de requête sur une table qui a une relation un-à-plusieurs. Que faire si je souhaite mapper vers un bean imbriqué?

Project.java


@Data
@ToString(exclude = {"tickets"})
public class Project {
    private int projectId;
    private String name;
    private List<Ticket> tickets;
}

Ticket.java


@Data
@ToString(exclude = {"comments"})
public class Ticket {
    private int ticketId;
    private String content;
    private List<Comment> comments;
}

Comment.java


@Data
public class Comment {
    private int commentId;
    private String content;
}

Répondre

Utilisez les fonctionnalités resultMap et collection. Dans l'exemple ci-dessus, créez le xml suivant.

ProjectMapper.xml


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ProjectMapper">
  <select id="findAllProject" resultMap="findAllProjectResultMap">
    SELECT
      project.project_id,
      project.name as project_name,
      ticket.ticket_id,
      ticket.content as ticket_content,
      comment.comment_id,
      comment.content as comment_content
    FROM project
    JOIN ticket ON project.project_id = ticket.project_id
    JOIN comment ON ticket.ticket_id = comment.ticket_id
  </select>

  <resultMap id="findAllProjectResultMap" type="com.example.demo.dto.Project">
    <id property="projectId" column="project_id" />
    <result property="name" column="project_name"/>
    <collection property="tickets" ofType="com.example.demo.dto.Ticket">
      <id property="ticketId" column="ticket_id" />
      <result property="content" column="ticket_content"/>
      <collection property="comments" ofType="com.example.demo.dto.Comment">
        <id property="commentId" column="comment_id" />
        <result property="content" column="comment_content"/>
      </collection>
    </collection>
  </resultMap>
</mapper>

Dans le code ci-dessous, vous pouvez vérifier comment le résultat de l'exécution de SQL est mappé à Java Bean par Pretty Print.

CommandlineappliApplication.java


@Component
public class CommandlineappliApplication implements CommandLineRunner{

    @Autowired
    private ProjectMapper projectMapper;

    @Override
    public void run(String... args) throws Exception {
        for (Project project : projectMapper.findAllProject()) {
            System.out.printf("%s%n", project);

            for (Ticket ticket : project.getTickets()) {
                System.out.printf("  └ %s%n", ticket);

                for (Comment comment : ticket.getComments()) {
                    System.out.printf("      └ %s%n", comment);
                }
            }
        }
    }
}

Le résultat de l'opération réelle est le suivant. Vous pouvez voir que le résultat de l'exécution SQL est mappé au bean imbriqué comme prévu.

Project(projectId=1, name=Projet 1)
  └ Ticket(ticketId=1, content=Billet 1-1)
      └ Comment(commentId=1, content=Commentaire 1-1-1)
      └ Comment(commentId=2, content=Commentaire 1-1-2)
  └ Ticket(ticketId=2, content=Billet 1-2)
      └ Comment(commentId=3, content=Commentaire 1-2-1)
      └ Comment(commentId=4, content=Commentaire 1-2-2)
Project(projectId=2, name=Projet 2)
  └ Ticket(ticketId=3, content=Billet 2-1)
      └ Comment(commentId=5, content=Commentaire 2-1-1)
      └ Comment(commentId=6, content=Commentaire 2-1-2)
  └ Ticket(ticketId=4, content=Billet 2-2)
      └ Comment(commentId=7, content=Commentaire 2-2-1)
      └ Comment(commentId=8, content=Commentaire 2-2-2)

Informations environnementales

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>mybatis-sample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>mybatis-sample</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>11</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-batch</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.3</version>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.batch</groupId>
			<artifactId>spring-batch-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Recommended Posts

[MyBatis] Je souhaite mapper une requête de requête à une table qui a une relation un-à-plusieurs avec un bean imbriqué.
Je souhaite utiliser le balayage arrière sur un écran qui utilise XLPagerTabStrip
Je souhaite développer une application web!
Je veux écrire un joli build.gradle
Je veux écrire un test unitaire!
[Android] Je souhaite créer un ViewPager pouvant être utilisé pour les didacticiels
[Ruby] Je veux faire un saut de méthode!
Je veux écrire une simple répétition d'une chaîne de caractères
Je souhaite concevoir une structure pour la gestion des exceptions
Je souhaite établir une connexion lorsqu'une base de données est créée à l'aide de Spring et MyBatis
Je souhaite utiliser PowerMock dans une classe qui combine des tests paramétrés et des tests ordinaires
7 choses que je veux que tu gardes pour que ça ne devienne pas un putain de code
Une histoire à laquelle j'étais accro lors de l'obtention d'une clé qui a été automatiquement essayée sur MyBatis
Je veux appeler une méthode d'une autre classe
Flux appris (je veux convertir la liste en carte <Integer, List>)
Je veux utiliser une petite icône dans Rails
Je souhaite surveiller un fichier spécifique avec WatchService
Je souhaite définir une fonction dans la console Rails
Je veux arrêter les cas de serpent avec des définitions de table
Je veux cliquer sur une broche GoogleMap dans RSpec
Je souhaite créer une annotation générique pour un type
Je souhaite ajouter une fonction de suppression à la fonction de commentaire
Je veux écrire une boucle qui fait référence à un index avec l'API Stream de Java 8