Spring Boot (JPA) CrudRepository 中自动生成的 SQL 查询不正确

Incorrect auto-generated SQL query in Spring Boot (JPA) CrudRepository

我的存储库接口:

SongsRepository:

public interface SongRepository extends CrudRepository<Song, Integer> {
    
}

AlbumsRepository

public interface AlbumRepository extends CrudRepository<Album, Integer> {
    
}

我的模型classes:

Album.java

@Entity
@Table(name = "albums", schema = "dbo")
public class Album {
    
    @Id
    @GeneratedValue
    @Column(name = "album_id")
    private Integer albumId;
    
    @Column(name = "album_name")
    private String albumName;
    
    @Column(name = "released_by")
    private String releasedBy;
    
    @Column(name = "total_duration")
    private Integer totalDuration;
    
    @OneToMany(targetEntity = Song.class)
    private List<Song> songs;

    public Integer getAlbumId() {
        return albumId;
    }

    public void setAlbumId(Integer albumId) {
        this.albumId = albumId;
    }

    public String getAlbumName() {
        return albumName;
    }

    public void setAlbumName(String albumName) {
        this.albumName = albumName;
    }

    public String getReleasedBy() {
        return releasedBy;
    }

    public void setReleasedBy(String releasedBy) {
        this.releasedBy = releasedBy;
    }

    public Integer getTotalDuration() {
        return totalDuration;
    }

    public void setTotalDuration(Integer totalDuration) {
        this.totalDuration = totalDuration;
    }

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

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

Song.java

@Entity
@Table(name = "songs", schema = "dbo")
public class Song {
    @Id
    @GeneratedValue
    @Column(name = "song_id")
    private Integer songId;

    @Column(name = "song_name")
    private String songName;
    
    @Column(name = "album_id")
    private Integer songAlbumId;
    
    @Column(name = "song_duration")
    private String songDuration;
    
    @ManyToOne(targetEntity = Album.class)
    private Album album;

    public Integer getSongId() {
        return songId;
    }

    public void setSongId(Integer songId) {
        this.songId = songId;
    }

    public String getSongName() {
        return songName;
    }

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

    public Integer getSongAlbumId() {
        return songAlbumId;
    }

    public void setSongAlbumId(Integer songAlbumId) {
        this.songAlbumId = songAlbumId;
    }

    public String getSongDuration() {
        return songDuration;
    }

    public void setSongDuration(String songDuration) {
        this.songDuration = songDuration;
    }

    public Album getAlbum() {
        return album;
    }

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

我的控制器:

SongsController.java

@RestController
@RequestMapping("/songs")
public class SongsController {
    
    @Autowired
    private SongRepository songs;
    
    @Autowired 
    private AlbumRepository albums;
    
    @Autowired
    private Services services;
    
    @GetMapping("/")
    public List<SongViewModel> getAllSongs() {
        List<SongViewModel> listOfAllSongs = new ArrayList<>();
        songs.findAll().forEach(song -> listOfAllSongs.add(services.translateToViewModel(song)));
        return listOfAllSongs;
    }
}

服务class:

Services.java:

@Service
public class Services {

    @Autowired
    private SongRepository songs;
    
    @Autowired
    private AlbumRepository albums;
    
    public SongViewModel translateToViewModel(Song song) {
        SongViewModel model = new SongViewModel();
        model.setSongId(song.getSongId());
        model.setSongAlbumId(song.getSongAlbumId());
        model.setSongName(song.getSongName());
        model.setSongDuration(song.getSongDuration());
        model.setSongAlbumName(albums.findById(song.getSongAlbumId()).get().getAlbumName());
        return model;
    }
    
    public AlbumViewModel translateToViewModel(Album album) {
        AlbumViewModel model = new AlbumViewModel();
        
        return model;
    }
}

我的视图模型:

SongViewModel:

public class SongViewModel {
    private String songName;
    private String songAlbumName;
    private String songDuration;
    private Integer songId;
    private Integer songAlbumId;
    public String getSongName() {
        return songName;
    }
    public void setSongName(String songName) {
        this.songName = songName;
    }
    public String getSongAlbumName() {
        return songAlbumName;
    }
    public void setSongAlbumName(String songAlbumName) {
        this.songAlbumName = songAlbumName;
    }
    public String getSongDuration() {
        return songDuration;
    }
    public void setSongDuration(String songDuration) {
        this.songDuration = songDuration;
    }
    public Integer getSongId() {
        return songId;
    }
    public void setSongId(Integer songId) {
        this.songId = songId;
    }
    public Integer getSongAlbumId() {
        return songAlbumId;
    }
    public void setSongAlbumId(Integer songAlbumId) {
        this.songAlbumId = songAlbumId;
    }
}

已记录 SQL 查询:
select song0_.song_id as song_id1_1_, song0_.album_album_id as album_al5_1_, song0_.album_id as album_id2_1_, song0_.song_duration as song_dur3_1_, song0_.song_name as song_nam4_1_ from dbo.songs song0_


错误:
ERROR: column song0_.album_album_id does not exist


My Database Schema (PostgreSQL 12.10.1)


这是我第一次使用 Spring Boot 和 JPA。我在这里做错了什么?


根据错误消息,我猜测它正在尝试查找一个名为 album_album_id 的列,该列在我的数据库中不存在,因此无法找到;但为什么要搜索那个特定的列? (我的猜测是我弄乱了关系属性)。

您的 Song 实体 class 应更改如下。

@Entity
@Table(name = "songs", schema = "dbo")
public class Song {
    @Id
    @GeneratedValue
    @Column(name = "song_id")
    private Integer songId;

    @Column(name = "song_name")
    private String songName;
    
    @Column(name = "song_duration")
    private String songDuration;
    
    @JoinColumn(name = "album_id", referencedColumnName = "album_id")
    @ManyToOne
    private Album album;

    public Integer getSongId() {
        return songId;
    }

    public void setSongId(Integer songId) {
        this.songId = songId;
    }

    public String getSongName() {
        return songName;
    }

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

    public Integer getSongAlbumId() {
        return songAlbumId;
    }

    public void setSongAlbumId(Integer songAlbumId) {
        this.songAlbumId = songAlbumId;
    }

    public String getSongDuration() {
        return songDuration;
    }

    public void setSongDuration(String songDuration) {
        this.songDuration = songDuration;
    }

    public Album getAlbum() {
        return album;
    }

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

现在您可以通过 song 实体使用 song.getAlbum().getAlbumId()

获得 alubm_id

你的映射有误。 Song 应该是这样的:

@Entity
@Table(name = "songs", schema = "dbo")
public class Song {
  @Id
  @GeneratedValue
  @Column(name = "song_id")
  private Integer id;

  @Column(name = "song_name")
  private String name;
    
  @Column(name = "album_id")
  private Integer albumId;
    
  @Column(name = "song_duration")
  private String duration;
    
  @ManyToOne
  @JoinColumn(name = "album_id", insertable = false, updatable = false)
  private Album album;
} 

Album像这样:

@Entity
@Table(name = "albums", schema = "dbo")
public class Album {
  @Id
  @GeneratedValue
  @Column(name = "album_id")
  private Integer id;
  
  @Column(name = "album_name")
  private String name;
  
  @Column(name = "released_by")
  private String releasedBy;
  
  @Column(name = "total_duration")
  private Integer totalDuration;
  
  @OneToMany(mappedBy = "album")
  private List<Song> songs;
}

顺便说一句,

  1. 歌曲时长格式为字符串,专辑时长格式为整数有点奇怪。
  2. 如果您愿意从 CrudRepository 转到 JpaRepository,您可能想使用 Spring data projection 而不是手动将您的歌曲重播到 SongViewModels

Here's a little example of interface projection for your question