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;
}
顺便说一句,
- 歌曲时长格式为字符串,专辑时长格式为整数有点奇怪。
- 如果您愿意从 CrudRepository 转到 JpaRepository,您可能想使用 Spring data projection 而不是手动将您的歌曲重播到 SongViewModels
Here's a little example of interface projection for your question
我的存储库接口:
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;
}
顺便说一句,
- 歌曲时长格式为字符串,专辑时长格式为整数有点奇怪。
- 如果您愿意从 CrudRepository 转到 JpaRepository,您可能想使用 Spring data projection 而不是手动将您的歌曲重播到 SongViewModels
Here's a little example of interface projection for your question