spring-data-jpa SPRING Boot - @OneToMany和我的集合〈>为空

iq3niunx  于 2022-11-10  发布在  Spring
关注(0)|答案(2)|浏览(172)

我问这个问题是因为我的OneToMany没有将对象添加到我的集合中。我想知道是我犯了一个错误还是我在配置中遗漏了什么。下面是我的代码:
application.properties :

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=${SMTP_SPREE_USERNAME}
spring.mail.password=${SMTP_SPREE_PASSWORD}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

server.servlet.context-path=/api
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/Workshop
spring.datasource.username=${SPREE_DB_USERNAME}
spring.datasource.password=${SPREE_DB_PASSWORD}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

jwt.secret=${SPREE_JWT_SECRET}

ActivityCategory.java :

package com.spreeapi.spree.models;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.Set;

@Entity
@Getter
@Setter
@Table(name="activity_category")
public class ActivityCategory {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "title")
    private String title;

    @OneToMany(targetEntity = Activity.class,
    cascade = CascadeType.ALL,
    fetch = FetchType.EAGER)
    private Set<Activity> activities;
}

Activity.java :

package com.spreeapi.spree.models;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

@Entity
@Table(name = "activity")
@Getter
@Setter
public class Activity {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "title")
    private String title;

    @Column(name = "description")
    private String description;

    @Column(name = "min_persons")
    private String minimalPersons;

    @Column(name = "max_persons")
    private String maximumPersons;

    @Column(name = "is_remote")
    private boolean isRemote;

    @Column(name = "working_hours")
    private boolean workingHours;

    @Column(name = "minimal_duration")
    private String minimalDuration;

    @ManyToOne(targetEntity = ActivityCategory.class)
    @JoinColumn(name = "activity_category_id")
    private ActivityCategory activityCategory;
}

ActivityCategoryRepository.java :

package com.spreeapi.spree.repository;

import com.spreeapi.spree.models.ActivityCategory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ActivityCategoryRepository extends JpaRepository<ActivityCategory, Integer> {
}

ActivityRepository.java :

package com.spreeapi.spree.repository;

import com.spreeapi.spree.models.Activity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ActivityRepository extends JpaRepository<Activity, Long> {
    public Page<Activity> findByActivityCategoryId(int id, Pageable pageable);
}

Test.java :

package com.spreeapi.spree.controllers;

import com.spreeapi.spree.models.Activity;
import com.spreeapi.spree.models.ActivityCategory;
import com.spreeapi.spree.repository.ActivityCategoryRepository;
import com.spreeapi.spree.repository.ActivityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class Test {

    @Autowired
    private ActivityRepository activityRepository;

    @Autowired
    private ActivityCategoryRepository activityCategoryRepository;

    @GetMapping("/rest/demand/categories")
    public List<ActivityCategory> test3(){
        return activityCategoryRepository.findAll();
    }

    @GetMapping("/rest/demand/activities")
    public List<Activity> test(){
        return activityRepository.findAll();
    }
}

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.7.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.spree-api</groupId>
    <artifactId>spree</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spree</name>
    <description>spree</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
              <groupId>org.springframework.security</groupId>
              <artifactId>spring-security-test</artifactId>
              <scope>test</scope>
          </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

当我对/类别执行GET时,结果是:

[
    {
        "id": 1,
        "title": "Escape game",
        "activities": []
    },
    {
        "id": 2,
        "title": "Jeux de société",
        "activities": []
    },
    {
        "id": 3,
        "title": "Sports",
        "activities": []
    },
    {
        "id": 4,
        "title": "Voyage",
        "activities": []
    },
    {
        "id": 5,
        "title": "Laser-game",
        "activities": []
    },
    {
        "id": 6,
        "title": "Activité culturelle",
        "activities": []
    },
    {
        "id": 7,
        "title": "After Work",
        "activities": []
    },
    {
        "id": 8,
        "title": "Jeux de cartes",
        "activities": []
    },
    {
        "id": 9,
        "title": "Jeux Vidéo",
        "activities": []
    },
    {
        "id": 10,
        "title": "Jeux de Rôle sur Table",
        "activities": []
    },
    {
        "id": 11,
        "title": "Karaoké",
        "activities": []
    }
]

如您所见,ActivityCategory的activities属性返回空,但如果我通过获取DB的所有活动列表来执行此操作,则通过访问/activities可获得以下结果:

[
    {
        "id": 1,
        "title": "Escape Game",
        "description": "L'Escape Game est un jeu dont le but est à tenter de s’échapper d’une pièce en un temps limité. En groupe de 2 à 6 participants, les joueurs doivent chercher des indices disséminés dans une ou plusieurs pièces, puis les combiner pour avancer dans la salle.",
        "minimalPersons": "2",
        "maximumPersons": "50",
        "workingHours": true,
        "minimalDuration": "Quelques heures",
        "activityCategory": {
            "id": 1,
            "title": "Escape game",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 2,
        "title": "7 wonders",
        "description": "7 Wonders est un jeu de cartes ayant pour thème le développement de civilisations autour de chacune des sept Merveilles du monde en utilisant un système de draft.",
        "minimalPersons": "2",
        "maximumPersons": "7",
        "workingHours": true,
        "minimalDuration": "Quelques heures",
        "activityCategory": {
            "id": 2,
            "title": "Jeux de société",
            "activities": []
        },
        "remote": true
    },
    {
        "id": 3,
        "title": "Catan",
        "description": "Catan est un classique du jeux de société, un jeu de plateau stratégique mais convivial avec un principe d'échange de ressource.",
        "minimalPersons": "2",
        "maximumPersons": "7",
        "workingHours": true,
        "minimalDuration": "Quelques heures",
        "activityCategory": {
            "id": 2,
            "title": "Jeux de société",
            "activities": []
        },
        "remote": true
    },
    {
        "id": 4,
        "title": "Risk",
        "description": "Risk est un jeux de société inspiré du jeux de guerre, en plus simplifier, où votre but est de conquérique le monde.",
        "minimalPersons": "2",
        "maximumPersons": "6",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 2,
            "title": "Jeux de société",
            "activities": []
        },
        "remote": true
    },
    {
        "id": 5,
        "title": "Les demeures de l'épouvante",
        "description": "Les Demeures de l’Épouvante est un jeu de plateau coopératif d’horreur et d’enquête. Les joueurs y incarnent des investigateurs qui s’aventurent dans les salles sombres des demeures hantées d’Arkham",
        "minimalPersons": "2",
        "maximumPersons": "5",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 2,
            "title": "Jeux de société",
            "activities": []
        },
        "remote": true
    },
    {
        "id": 6,
        "title": "Foot",
        "description": "Le football est un sport collectif qui se joue avec un ballon sphérique, où il faut faire pénétrer un ballon rond dans les buts adverses sans utiliser les mains",
        "minimalPersons": "5",
        "maximumPersons": "100",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 3,
            "title": "Sports",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 7,
        "title": "Tennis de table",
        "description": "Le tennis de table, appelé aussi ping-pong, est un sport de raquette opposant deux ou quatre joueurs autour d'une table",
        "minimalPersons": "2",
        "maximumPersons": "100",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 3,
            "title": "Sports",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 8,
        "title": "Bowling",
        "description": "Le bowling est un jeu qui consiste à renverser des quilles à l'aide d'une boule.",
        "minimalPersons": "2",
        "maximumPersons": "10",
        "workingHours": true,
        "minimalDuration": "Quelques heures",
        "activityCategory": {
            "id": 3,
            "title": "Sports",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 9,
        "title": "Voyage",
        "description": "Un voyage en équipe est un bon moyen de souder ses équipes.",
        "minimalPersons": "5",
        "maximumPersons": "100",
        "workingHours": true,
        "minimalDuration": "1 journée",
        "activityCategory": {
            "id": 4,
            "title": "Voyage",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 10,
        "title": "Laser-game",
        "description": "Un jeu laser aussi connu sous le terme anglophone Laser tag est une activité physique où les participants, revêtus habituellement d'une veste à capteurs, se tirent dessus avec des « pistolets laser »",
        "minimalPersons": "2",
        "maximumPersons": "10",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 5,
            "title": "Laser-game",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 11,
        "title": "Musée",
        "description": "le musée est un lieu d'expériences mémorables et émouvantes quand les sens sont interpellés pour attirer, susciter la curiosité, amuser, émerveiller, faire comprendre.",
        "minimalPersons": "2",
        "maximumPersons": "100",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 6,
            "title": "Activité culturelle",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 12,
        "title": "After Work",
        "description": "Cet instant entre collègues permet de resserrer les liens, de souder les équipes, de créer une sorte d'émulation. C'est aussi un moment où l'on dresse un bilan, où l'on cherche à décompresser ensemble dans un lieu en soirée neutre et agréable, loin de l'ambiance du travail.",
        "minimalPersons": "2",
        "maximumPersons": "20",
        "workingHours": false,
        "minimalDuration": "Quelques heures",
        "activityCategory": {
            "id": 7,
            "title": "After Work",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 13,
        "title": "Poker",
        "description": "Le poker est une famille de jeux de cartes comprenant de nombreuses formules et variantes. Il se pratique à plusieurs joueurs avec un jeu généralement de cinquante-deux cartes et des jetons représentant les sommes misées. Les séquences de jeu alternent distribution de cartes et tours d'enchères.",
        "minimalPersons": "5",
        "maximumPersons": "50",
        "workingHours": true,
        "minimalDuration": "1/2 journées",
        "activityCategory": {
            "id": 8,
            "title": "Jeux de cartes",
            "activities": []
        },
        "remote": false
    },
    {
        "id": 14,
        "title": "Arcade",
        "description": "Une salle d’arcade est un établissement de loisirs regroupant des appareils tels que des jeux d’arcade, des flippers, des baby-foots, des tables d'air hockey, des machines attrape-jouet ainsi que des billards.",
        "minimalPersons": "10",
        "maximumPersons": "50",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 9,
            "title": "Jeux Vidéo",
            "activities": []
        },
        "remote": true
    },
    {
        "id": 15,
        "title": "Honey Heist",
        "description": "Y en a deux : OURS et CRIMINEL. Les deux commencent à 3. OURS sert à courir, escalader, péter des trucs, ignorer les dommages, effrayer les gens et autres trucs d’ours. CRIMINEL sert pour tous les autres trucs, ce que les ours ne font pas en général.",
        "minimalPersons": "3",
        "maximumPersons": "6",
        "workingHours": true,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 10,
            "title": "Jeux de Rôle sur Table",
            "activities": []
        },
        "remote": true
    },
    {
        "id": 16,
        "title": "Karaoké",
        "description": "Prends le micro et chante",
        "minimalPersons": "2",
        "maximumPersons": "110",
        "workingHours": false,
        "minimalDuration": "1/2 journée",
        "activityCategory": {
            "id": 11,
            "title": "Karaoké",
            "activities": []
        },
        "remote": false
    }
]

请让我知道,如果有什么是失踪或一个错误已作出。

wd2eg0qa

wd2eg0qa1#

ActivityCategoryActivity之间有两个独立的关系,它们完全不相关。
如果您希望上的是另一个的反转,则必须将mappedBy属性添加到@ManyToOne@OneToMany注解中。
请注意,没有mappedBy属性的一端定义了将保留到数据库的内容,而另一端将在从数据库重新加载信息后镜像该信息,由于一级缓存的原因,这不会在单个事务中发生。
有关详细信息,请阅读一级缓存和双向关系。

k2arahey

k2arahey2#

要添加到Jens Schauder答案(顺便说一下,非常好的解释性答案)。
@OneToMany应该知道如何MapActivityCategoryActivity。这可以像这样完成:

@OneToMany(mappedBy = "activityCategory", targetEntity = Activity.class,
cascade = CascadeType.ALL,
fetch = FetchType.EAGER)
private Set<Activity> activities;

相关问题