在Sping Boot 中使用JPA从具有OneToMany关系的实体中删除对象

k3fezbri  于 7个月前  发布在  其他
关注(0)|答案(2)|浏览(90)

下午好,我正在使用REST API,其中我有一个包含许多歌曲的播放列表,我使用JPA以及允许我在两者之间建立关系的好处。现在,如果我想删除已经添加到PlayList的歌曲,我不能这样做,我在下面向您展示我的类
班级播放列表

@Entity
@Table(name = "PLAY_LIST")
public class PlayList {

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

    //@JsonView(View.Get.class)
    @Column(name="name")
    private String name;

    //@JsonView(View.Get.class)
    @Column(name="description")
    private String description;

    //@JsonView(View.Get.class)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "playList")
    private List<Song> songs = new ArrayList<>();

    @Transient
    public void addSong(Song song) {
        song.setPlayList(this);
        songs.add(song);
    }

    @Transient
    public void removeSong(Song song) {
        songs.remove(song);
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<Song> getSongs() {
        return this.songs;
    }

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

字符串
这里我有添加歌曲和删除的方法,但是,删除对我不起作用。
班歌

Entity
@Table(name = "SONG")
public class Song{

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

    //@JsonView(View.Create.class)
    @Column(name = "title")
    private String title;

    //@JsonView(View.Create.class)
    @Column(name = "artist")
    private String artist;

    //@JsonView(View.Create.class)
    @Column(name = "album")
    private String album;

    //@JsonView(View.Create.class)
    @Column(name = "year")
    private int year;

    /* 

    Fetch: Esta propiedad se utiliza para determinar cómo debe ser cargada la entidad.
    LAZY (perezoso): Indica que la relación solo se cargará cuando la propiedad sea leída por primera vez */
    //@JsonView(View.Get.class)
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PLAY_LIST_ID")
    private PlayList playList;

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return this.title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getArtist() {
        return this.artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public String getAlbum() {
        return this.album;
    }

    public void setAlbum(String album) {
        this.album = album;
    }

    public int getYear() {
        return this.year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public PlayList getPlayList() {
        return this.playList;
    }

    public void setPlayList(PlayList playList) {
        this.playList = playList;
    }
    
}


我的类Controller

@RestController
@RequestMapping("playlist")
public class PlayListController {

   @Autowired
   private PlayListService playListService;

   @Autowired
   private SongRepository songRepository;

   // Get playlist by id with songs belongs that playlist

   @GetMapping("/get/{id}")
   public Optional<PlayList> getPlayListByID(@PathVariable(value = "id") Long id) {

      Optional<PlayList> playList = playListService.getById(id);
      return playList;
   }

   @PostMapping("/create")
   public PlayList createPlayList(@RequestBody PlayListDTO playListDTO) {

      PlayList playList = new PlayList();

      playList.setName(playListDTO.getName());
      playList.setDescription(playListDTO.getDescription());
      playList.setSongs(new ArrayList<>());

      for (int x=0; x<playListDTO.getSongs().size(); x++) {

         Song songs=new Song();
         songs.setTitle(playListDTO.getSongs().get(x).getTitle());
         songs.setArtist(playListDTO.getSongs().get(x).getArtist());
         songs.setAlbum(playListDTO.getSongs().get(x).getAlbum());
         songs.setYear(playListDTO.getSongs().get(x).getYear());
         playList.addSong(songs);

      }
        return playListService.savePlayList(playList);
     }
   @PutMapping("/update/{id}")
   public PlayList updatePlayList(@PathVariable(value = "id") Long id,@RequestBody Song song){

      PlayList playList = playListService.getById(id).get();
      song.setPlayList(playList);
      playList.getSongs().add(song);
      playListService.savePlayList(playList);
      return playList;
   }
   
   @DeleteMapping("/delete/{id}")
   public PlayList deletePlayList(@PathVariable(value = "id") Long id,@RequestBody Song song){
      PlayList playList =playListService.getById(id).get();
      System.out.println(playList.getSongs());
      playList.removeSong(song);
      System.out.println(playList.getSongs());
      return playList;
   }

}


因此,我存储播放列表及其歌曲,方法POST

{
    "name": "Lista 1",
    "description": "Lista de reproduccion 2020 spotify",
    "songs": [
        {
            "title": "Tan Enamorados",
            "artist": "CNCO",
            "album": "Tan Enamorados",
            "year": 2020
        },
        {
            "title": "Hawai",
            "artist": "Maluma",
            "album": "PAPI JUANCHO",
            "year": 2020
        }
    ]
}


现在,为了消除,我传递了播放列表的id和歌曲的请求(BD中自动创建的没有歌曲id的对象),但是,我不能从播放列表中消除歌曲,并且在日志级别,它返回了在控制台中打印的结果
例如,我想删除以下歌曲:


的数据
然而,它并没有被删除,它返回相同的列表给我
我是否错过了一些东西,可以删除一首歌曲,而不必删除播放列表?

twh00eeo

twh00eeo1#

使用PlayList中的所有歌曲列表删除歌曲并不是一个很好的主意。没有@OneToMany关联的连接表。所以我们可以使用SONG表更简单地删除歌曲(这是@OneToMany连接表不方便的主要原因)。
你需要一个歌曲ID,你需要使用CrudRepository.deleteById()方法。你可以使用完整的组合(标题,艺术家,专辑,年份),但更简单的是将歌曲ID添加到JSON中。
最好使用此端点URL删除歌曲
/{playListId}/songs/{songId}
您不需要在URL中使用delete部分,因为您已经使用了HTTP方法。

为什么你的代码不工作

1.从列表中使用删除方法不正确

@Transient
public void removeSong(Song song) {
    songs.remove(song);
}

字符串
songs.remove()在列表中找不到songList.remove()通过引用找到一首歌。它需要有一个开放的持久化上下文,并从中获取一首歌,才能在列表中找到它。
1.不使用事务(打开的持久化上下文)让Hibernate知道一首歌被删除了,Hibernate必须更新数据库。
所以一个合理的假设是

start @Transactional
  Spring starts a database transaction
  Spring opens a persistent context
  load PlayList
  load a song from the database (using id or other song attributes)
  delete a song from PlayList songs (or delete a song from PlayList songs using id)
end @Transactional
    
Hibernate flushes changes and delete a song in the database
persistent context is closed
database transaction is committed

ax6ht2ek

ax6ht2ek2#

{
    "name": "Lista 1",
    "description": "Lista de reproduccion 2020 spotify",
    "songs": [
        {
            "title": "Tan Enamorados",
            "artist": "CNCO",
            "album": "Tan Enamorados",
            "year": 2020
        },
        {
            "title": "Hawai",
            "artist": "Maluma",
            "album": "PAPI JUANCHO",
            "year": 2020
        }
    ]
}

字符串

相关问题