在 Spring Boot 中使用多对多时出现空集合

问题描述 投票:0回答:1
package musicstore.musicselling.Entity;

import java.util.Set;
import java.util.HashSet;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;

@Entity
@Table(name = "artist")
public class Artist {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long artistId;
    private String artistName;
    private String artistBio;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "artist_song", joinColumns = {
            @JoinColumn(name = "artist_id", referencedColumnName = "artistId") }, inverseJoinColumns = {
                    @JoinColumn(name = "song_id", referencedColumnName = "songId") })
    private Set<Song> songs = new HashSet<>();

    public Artist() {

    }

    public Artist(String artistName, String artistBio) {
        this.artistName = artistName;
        this.artistBio = artistBio;
    }

    public Long getArtistId() {
        return artistId;
    }

    public String getArtistName() {
        return artistName;
    }

    public void setArtistName(String artistName) {
        this.artistName = artistName;
    }

    public String getArtistBio() {
        return artistBio;
    }

    public void setArtistBio(String artistBio) {
        this.artistBio = artistBio;
    }

    public Set<Song> getSongs() {
        return songs;
    }

    public void setSongs(Set<Song> songs) {
        this.songs = songs;

    }

    public void addSong(Song song) {
        this.songs.add(song);
        song.getArtists().add(this);
    }

}
package musicstore.musicselling.Entity;

import java.util.Set;
import java.util.HashSet;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;

@Entity
@Table(name = "song")
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long songId;
    private String songName;
    private long songStream;

    @ManyToMany(mappedBy = "songs", fetch = FetchType.EAGER)
    private Set<Artist> artists = new HashSet<>();

    public Song() {

    }

    public Song(String songName, long songStream) {
        this.songName = songName;
        this.songStream = songStream;
        this.artists = new HashSet<>();
    }

    public Long getSongId() {
        return songId;
    }

    public String getSongName() {
        return songName;
    }

    public void setSongName(String songName) {
        this.songName = songName;
    }

    public long getSongStream() {
        return songStream;
    }

    public void setSongStream(long songStream) {
        this.songStream = songStream;
    }

    public Set<Artist> getArtists() {
        return artists;
    }

    public void setArtists(Set<Artist> artists) {
        this.artists = artists;
    }

    public void addArtist(Artist artist) {
        this.artists.add(artist);
        artist.getSongs().add(this);
    }

}
package musicstore.musicselling;

import java.util.Set;
import java.util.HashSet;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import jakarta.transaction.Transactional;
import musicstore.musicselling.Entity.Artist;
import musicstore.musicselling.Entity.Song;
import musicstore.musicselling.Repository.ArtistRepository;
import musicstore.musicselling.Repository.SongRepository;

@SpringBootApplication
public class MusicsellingApplication {
    @Autowired
    private SongRepository songRepository;

    @Autowired
    private ArtistRepository artistRepository;

    public static void main(String[] args) {
        SpringApplication.run(MusicsellingApplication.class, args);
    }

    @Bean
    @Transactional
    public CommandLineRunner commandLineRunner() {
        return args -> {
            // create artists
            Artist artist1 = new Artist("Sơn Tùng M-TP", "Vietnamese singer-songwriter and actor.");
            Artist artist2 = new Artist("tlinh", "tlinh is a Vietnamese independent singer and rapper.");
            Artist artist3 = new Artist("RPT MCK", "RPT MCK is a Vietnamese singer and rapper based in Ha Noi.");

            // save artists
            artistRepository.save(artist1);
            artistRepository.save(artist2);
            artistRepository.save(artist3);

            // Create songs and add artists
            Song song1 = new Song("nếu lúc đó", 3794587);
            song1.addArtist(artist2);

            Song song2 = new Song("Chạy Ngay Đi", 234879825);
            song2.addArtist(artist1);

            Song song3 = new Song("Hãy Trao Cho Anh", 2387532);
            song3.addArtist(artist1);

            Song song4 = new Song("Chỉ Một Đêm Nữa Thôi (feat. tlinh)", 782643);
            song4.addArtist(artist2);
            song4.addArtist(artist3);

            Song song5 = new Song("Em Là Châu Báu", 298374);
            song5.addArtist(artist2);
            song5.addArtist(artist3);

            // save songs
            songRepository.save(song1);
            songRepository.save(song2);
            songRepository.save(song3);
            songRepository.save(song4);
            songRepository.save(song5);

        };
    }
}
package musicstore.musicselling.Repository;

import org.springframework.data.jpa.repository.JpaRepository;

import musicstore.musicselling.Entity.Artist;

public interface ArtistRepository extends JpaRepository<Artist, Long> {

}
package musicstore.musicselling.Repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import musicstore.musicselling.Entity.Song;

@Repository
public interface SongRepository extends JpaRepository<Song, Long> {

}

这是我的代码,当我尝试运行应用程序时,artist_song 表没有填充任何数据,尽管其他两个表都填充了数据。

谁能告诉我artist_song表的数据没有填充的原因吗?

我尝试了很多方法,包括将 FetchType 从 LAZY 更改为 EAGER,但仍然不起作用

postgresql spring-boot many-to-many
1个回答
0
投票

该问题与级联操作有关。您声明

Artist
为关系的所有者方,而您的目标方是
Song
。您首先存储艺术家,然后将这些艺术家添加到歌曲中,最后在应该相反的情况下保存这些歌曲。顺便说一句,当您在所有者端使用属性
CascadeType.ALL
时,不需要先保存目标端,然后将目标端添加到所有者端并保存。您可以先将目标端添加到所有者端,然后保存(所有者端)。

您有两个选择,将

Song
设置为主侧或修改在数据库中存储实体的方式。

第一个选项:

在你的班级

Song
:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
        name = "artist_song", 
        joinColumns = { @JoinColumn(name = "song_id", nullable = false) }, 
        inverseJoinColumns = {@JoinColumn(name = "artist_id", nullable = false)
})
private Set<Artist> artists = new HashSet<>();

在你的班级

Artist
:

@ManyToMany(mappedBy = "artists")
private Set<Song> songs = new HashSet<>();

坚持类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import app.entity.Artist;
import app.entity.Song;
import app.repository.ArtistRepository;
import app.repository.SongRepository;
import jakarta.transaction.Transactional;

@Component
public class Persistence implements CommandLineRunner {

    @Autowired
    private ArtistRepository artistRepository;

    @Autowired
    private SongRepository songRepository;

    @Override
    @Transactional
    public void run(String... args) throws Exception {
        // Create artists
        Artist artist1 = new Artist("Sơn Tùng M-TP", "Vietnamese singer-songwriter and actor.");
        Artist artist2 = new Artist("tlinh", "tlinh is a Vietnamese independent singer and rapper.");
        Artist artist3 = new Artist("RPT MCK", "RPT MCK is a Vietnamese singer and rapper based in Ha Noi.");

        // Create songs and add artists
        Song song1 = new Song("nếu lúc đó", 3794587);
        song1.addArtist(artist2);

        Song song2 = new Song("Chạy Ngay Đi", 234879825);
        song2.addArtist(artist1);

        Song song3 = new Song("Hãy Trao Cho Anh", 2387532);
        song3.addArtist(artist1);

        Song song4 = new Song("Chỉ Một Đêm Nữa Thôi (feat. tlinh)", 782643);
        song4.addArtist(artist2);
        song4.addArtist(artist3);

        Song song5 = new Song("Em Là Châu Báu", 298374);
        song5.addArtist(artist2);
        song5.addArtist(artist3);

        // Save songs, which will cascade and save artists as well
        songRepository.save(song1);
        songRepository.save(song2);
        songRepository.save(song3);
        songRepository.save(song4);
        songRepository.save(song5);
    }

}

第二个选项:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import app.entity.Artist;
import app.entity.Song;
import app.repository.ArtistRepository;
import app.repository.SongRepository;
import jakarta.transaction.Transactional;

@Component
public class Persistence implements CommandLineRunner {

    @Autowired
    private ArtistRepository artistRepository;

    @Autowired
    private SongRepository songRepository;

    @Override
    @Transactional
    public void run(String... args) throws Exception {
        // Create songs
        Song song1 = new Song("nếu lúc đó", 3794587);
        Song song2 = new Song("Chạy Ngay Đi", 234879825);
        Song song3 = new Song("Hãy Trao Cho Anh", 2387532);
        Song song4 = new Song("Chỉ Một Đêm Nữa Thôi (feat. tlinh)", 782643);
        Song song5 = new Song("Em Là Châu Báu", 298374);
    
        // Create artists
        Artist artist1 = new Artist("Sơn Tùng M-TP", "Vietnamese singer-songwriter and actor.");
        Artist artist2 = new Artist("tlinh", "tlinh is a Vietnamese independent singer and rapper.");
        Artist artist3 = new Artist("RPT MCK", "RPT MCK is a Vietnamese singer and rapper based in Ha Noi.");

        // Establish relationships
        artist1.addSong(song2);
        artist1.addSong(song3);
    
        artist2.addSong(song1);
        artist2.addSong(song4);
        artist2.addSong(song5);
    
        artist3.addSong(song4);
        artist3.addSong(song5);

        // Save artists, which will cascade and save songs as well
        artistRepository.save(artist1);
        artistRepository.save(artist2);
        artistRepository.save(artist3);
    }

}

我将实体存储在一个名为

Persistence
的新类中,因为我复制了您的代码,它给了我一个例外:
Detached Entity Passed to Persist

您仍然可以在

MusicsellingApplication
方法中的
commandLineRunner
类中实现它,但您必须删除所有者端的属性
cascade = CascadeType.PERSIST
。这是因为Spring也会尝试保存关联的对象(歌曲)。但是,此对象未附加到此会话(分离异常的原因)。

© www.soinside.com 2019 - 2024. All rights reserved.