我认为最好的办法是在此处构建一个DTO,以帮助我了解2个表的关系,但是,我不知道在执行get时如何以允许我的方式进行操作从播放列表中获取仅idPlayList,然后在省电时将idPlayList传递到将要与播放列表一起保存的每首歌曲中,或者是否可以通过其他方式存储包含歌曲的播放列表并进行存储直接,因为目前我必须由BD分配给每首歌曲idPlayList 解决方案 在 application.properties 中添加 spring.jpa.open-in-view = false ,以使其具有 LazyInitializationException .这将有助于建立良好的查询.这是什么spring.jpa在Spring Boot中是.open-in-view = true属性? 使用带有 LEFT JOIN FETCH 的JPQL查询,使用 songs 加载 PlayList ,以从列表中提取歌曲.因此,歌曲已被加载,歌曲中的 playList 将变得很懒. @EntityGraph 也可以使用.从播放列表的列表中的 select列表左联接获取list.songs,其中list.id =:listId 杰克逊中有 Hibernate5Module .它允许省略懒惰的关联.因此,杰克逊不会触摸歌曲中的 playList .配置Jackson以忽略Spring Boot中的延迟加载属性 构建类似于真实系统的东西.您可以添加 PlayListResponse , SongResponse 类,并将实体映射到服务级别上的那些类.在这种情况下,您可能不需要 Hibernate5Module .但是最好也尝试使用此模块. 启用在 application.properties 中记录数据库 logging.level.org.springframework.transaction.interceptor = TRACElogging.level.org.springframework.orm.jpa.JpaTransactionManager = DEBUGlogging.level.org.hibernate.SQL =调试spring.jpa.properties.hibernate.use_sql_comments = true 仔细检查日志中的事务和SQL.不允许Hibernate产生不必要的查询. 如何使用列表保存歌曲 将此方法添加到 PlayList @Transientpublic void addSong(歌曲){song.setPlayList(this);songs.add(song);} 使用 addSong()方法将歌曲添加到列表中.保存 PlayList .Hibernate将使用正确的列表ID保存列表中的所有歌曲,因为 @OneToMany 中有 cascade = CascadeType.ALL .Good morning, nice to greet you.I am new to Spring Boot recently, and I am working with a REST API, which is basically a playlist with songs, basically the REST API should have the following structure. A playlist can have many songs:{ "name": "Lista 1", "description": "Lista de reproduccion 2020 spotify", "songs": [ { "title": "Tan Enamorados", "artist": "CNCO", "album": "Tan Enamorados", "year": 2020, "playList": 1 }, { "title": "Hawai", "artist": "Maluma", "album": "PAPI JUANCHO", "year": 2020, "playList": 1 } ]}Currently this is how I have my entities configuredEntity SONGS@Entity@Table(name = "SONGS")public class Songs{ @JsonIgnore @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(name = "ID") private Long id; @Column(name = "title") private String title; @Column(name = "artist") private String artist; @Column(name = "album") private String album; @Column(name = "year") private int year; @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; } }Entity PLAYLIST@Entity@Table(name = "PLAY_LIST")public class PlayList { @JsonIgnore @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(name = "ID") private Long id; @Column(name="name") private String name; @Column(name="description") private String description; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "playList") private List<Songs> songs = new ArrayList<>(); 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<Songs> getSongs() { return this.songs; } public void setSongs(List<Songs> songs) { this.songs = songs; } }Controller@RestController@RequestMapping("playlist")public class PlayListController { @Autowired private PlayListService playListService; //Get playlist by id with songs belongs that playlist @GetMapping("/{id}") public Optional<PlayList> getPlayListByID(@PathVariable(value = "id") Long id) { Optional<PlayList> playList = playListService.getById(id); return playList; } @PostMapping("/create") public PlayList createPlayList(@RequestBody PlayList playList) { return playListService.savePlayList(playList); }}My class PlayListServiceImpl@Servicepublic class PlayListServiceImpl implements PlayListService { @Autowired private PlayListRepository playListRepository; public Optional <PlayList> getById(Long Id) { Optional <PlayList> playList= playListRepository.findById(Id); return playList; } @Override public PlayList savePlayList(PlayList playList) { return playListRepository.save(playList); } }My Repository@Repositorypublic interface PlayListRepository extends JpaRepository<PlayList, Long> { Optional<PlayList> findById(Long Id); }However, I have infinite recursion problem when I try to get a playlist with the get method:org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.example.api.songs.entity.PlayList[\"songs\"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.api.songs.entity.Songs[\"playList\"]->com.example.api.songs.entity.PlayList[\"songs\"]->org.hibernate.This is due to the playList field found in the Songs entity, when trying to get the playlist with the songs, I get an array that becomes recursive and not the id of the playList, which is what I want to get, the reality is that I get something like this:I can solve by applying a JsonIgnore in the field, however this affects me that when I go to save a playlist, I cannot pass the idPlayList field to each song to make sure that each song is saved with its respective idPlayListI think the best thing would be to build a DTO here that helps me to have the relationship of the 2 tables, however, I don't know how I would do it in a way that allows me, when executing a get from the playList, to obtain only the idPlayList, and when saving power pass the idPlayList in each song that is going to be saved with a playlist, or if there is another way in which I could store a playlist with its songs and have them stored directly, since currently I have to assign by BD to each song the idPlayList 解决方案 Add spring.jpa.open-in-view=false to the application.properties to have LazyInitializationException. It will help to build good queries.What is this spring.jpa.open-in-view=true property in Spring Boot?Load PlayList with songs using JPQL query with LEFT JOIN FETCH to fetch songs with the list. So songs will be already loaded and playList in the song will be lazy. @EntityGraph can be used also.select list from PlayList list left join fetch list.songs where list.id = :listIdThere is Hibernate5Module in Jackson. It allow to omit lazy associations. So Jackson will not touch playList in the song.Configure Jackson to omit lazy-loading attributes in Spring BootTo build something like a real system. You can add PlayListResponse, SongResponse classes and map entities to those classes on the service level. Probably you will not need Hibernate5Module in this case. But better to experiment with this module too.Enable database logging in application.properties withlogging.level.org.springframework.transaction.interceptor=TRACElogging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUGlogging.level.org.hibernate.SQL=DEBUGspring.jpa.properties.hibernate.use_sql_comments=trueCheck transactions and SQL in the logs carefully. Don't allow Hibernate to produce unnecessary queries.How to save the songs with a listAdd this method to the PlayList@Transientpublic void addSong(Song song) { song.setPlayList(this); songs.add(song);}Add songs to the list using addSong() method.Save PlayList. All the songs of a list will be saved by Hibernate with the correct list id, because there is cascade = CascadeType.ALL in the @OneToMany. 这篇关于如何在Spring Boot中从双向表关系生成DTO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-19 13:15