Java 在Spring Boot中使用JPA从两者之间具有一对一关系的实体中删除对象
下午好,我正在使用一个RESTAPI,其中我有一个包含许多歌曲的播放列表,为此我使用了JPA,它的优点使我能够建立两者之间的关系。现在,如果我想删除一首已经添加到播放列表中的歌曲,我无法删除,我将在下面向您展示我的课程 类播放列表Java 在Spring Boot中使用JPA从两者之间具有一对一关系的实体中删除对象,java,spring-boot,jpa,orm,Java,Spring Boot,Jpa,Orm,下午好,我正在使用一个RESTAPI,其中我有一个包含许多歌曲的播放列表,为此我使用了JPA,它的优点使我能够建立两者之间的关系。现在,如果我想删除一首已经添加到播放列表中的歌曲,我无法删除,我将在下面向您展示我的课程 类播放列表 @Entity @Table(name = "PLAY_LIST") public class PlayList { @JsonIgnore @Id @GeneratedValue(strategy = Generatio
@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;
}
}
我的班长
@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;
}
}
现在,为了消除,我正在传递播放列表的id和歌曲的请求(没有在BD中自动创建的歌曲id的对象),但是,我无法从播放列表中消除歌曲,并且在日志级别,它在控制台中执行打印时返回此消息
例如,我想删除以下歌曲:
但是它不会被删除,它会将相同的列表返回给我
我是否错过了一些可以删除歌曲而不必删除播放列表的功能?使用
播放列表中的所有歌曲列表删除歌曲不是一个好主意。
没有用于@OneToMany
关联的联接表。因此,我们可以使用song
table更简单地删除歌曲(这是@OneToMany
的联接表不方便的主要原因)
为此,您需要一个歌曲id,并且需要使用crudepository.deleteById()
方法。
您可以使用完整的组合(标题、艺术家、专辑、年份),但在JSON中添加歌曲id要简单得多
最好使用此端点URL删除歌曲
/{playlyid}/songs/{songId}
您不需要删除URL中的部分,您已经使用了删除HTTP方法
为什么您的代码不起作用
使用列表中的delete方法不正确
songs.remove()
在列表中找不到song
,list.remove()
通过引用查找歌曲。它需要有一个开放的持久上下文,并从中获取一首歌曲,才能在列表中找到它
不使用事务(打开的持久上下文)让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
非常感谢,我发现删除歌曲的好方法是通过对象歌曲和方法http delete删除,发送歌曲id。使用OneToMany的缺点是什么?我很好奇Spotify播放列表在现实生活中是如何通过关系工作的,这就是我想要做的this@CesarJusto如果要使用@OneToMany
收藏删除一首歌曲,必须从数据库中加载所有歌曲,从收藏中删除一首歌曲,并与歌曲一起保存播放列表。Hibernate将删除一条记录,当然不会更新所有内容。@CesarJusto使用歌曲集可能很有用,如果用户更改了歌曲集的一些元素,那么您可以使用merge()
方法添加或删除多个元素。要使用@OneToMay删除歌曲,我使用实体song和remove方法删除一首歌曲,然后使用相同的id?再次保存列表,或者按照这种情况下的过程,因为我尝试使用song实体中的remove函数进行删除,然后通过save函数再次保存,但它仍然没有返回更新的列表,或者我不知道它是否创建了一个新列表
{
"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
}
]
}
@Transient
public void removeSong(Song song) {
songs.remove(song);
}
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