[英]Hibernate/Spring Data not fetching collection in OneToMany mapping
我在Hibernate中有一個一對多的映射,當我嘗試通過Spring JPARepository將其從數據庫中移出時,總是給我一個空集合。
我有一個看起來像這樣的User類。
@Indexed
@Entity
@Table(name="usr", indexes = {@Index(columnList = "email", unique = true)})
public class User{
private Long userId;
private String email;
private String firstname;
private String lastname;
private String phone;
private String passwordHash;
private Set<PollOption> votes;
private Set<FriendsList> friendsList;
//no args constructor
public User() {
votes = new HashSet<>();
friendsList = new HashSet<>();
}
/**
* Gets the value of id
*
* @return the value of id
*/
@Id
@GenericGenerator(name = "userautoinc", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "userautoinc"),
@Parameter(name = "optimizer", value = "hilo"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1") }
)
@GeneratedValue(generator = "userautoinc")
@Column(name="userid")
public Long getUserId() {
return this.userId;
}
/**
* Sets the value of id
*
* @param argId Value to assign to this.id
*/
public void setuserId(final Long argId) {
this.userId = argId;
}
/**
* Gets the value of email
*
* @return the value of email
*/
@Field
@NaturalId
@Column(name="email", nullable = false)
public String getEmail() {
return this.email;
}
/**
* Sets the value of email
*
* @param argEmail Value to assign to this.email
*/
public void setEmail(final String argEmail) {
this.email = argEmail;
}
/**
* Gets the value of firstname
*
* @return the value of firstname
*/
@Field
@Column(name="firstname", nullable = false)
public String getFirstname() {
return this.firstname;
}
/**
* Sets the value of firstname
*
* @param argFirstname Value to assign to this.firstname
*/
public void setFirstname(final String argFirstname) {
this.firstname = argFirstname;
}
/**
* Gets the value of lastname
*
* @return the value of lastname
*/
@Field
@Column(name="lastname", nullable = false)
public String getLastname() {
return this.lastname;
}
/**
* Sets the value of lastname
*
* @param argLastname Value to assign to this.lastname
*/
public void setLastname(final String argLastname) {
this.lastname = argLastname;
}
/**
* Gets the value of phone
*
* @return the value of phone
*/
@Column(name="phone", nullable = true)
public String getPhone() {
return this.phone;
}
/**
* Sets the value of phone
*
* @param argPhone Value to assign to this.phone
*/
public void setPhone(final String argPhone) {
this.phone = argPhone;
}
/**
* Gets the value of passwordHash
*
* @return the value of passwordHash
*/
@Column(name="passwordhash", nullable = false)
public String getPasswordHash() {
return this.passwordHash;
}
/**
* Sets the value of passwordHash
*
* @param argPasswordHash Value to assign to this.passwordHash
*/
public void setPasswordHash(final String argPasswordHash) {
this.passwordHash = argPasswordHash;
}
@ManyToMany(mappedBy = "voters", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Set<PollOption> getVotes(){
return this.votes;
}
public void setVotes(Set<PollOption> votes){
this.votes = votes;
}
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public Set<FriendsList> getFriendsList() {
return this.friendsList;
}
public void setFriendsList(Set<FriendsList> friendList) {
this.friendsList = friendsList;
}
//To String Method
@Override
public String toString() {
return "User [userId=" + userId + ", email=" + email + ", firstname=" + firstname + ", lastname=" + lastname
+ ", phone=" + phone + ", passwordHash=" + passwordHash + "]";
}
}
我的FriendsList實體(實際上是具有額外列的聯結表)如下所示:
@Entity
@Table(name = "friendslist")
public class FriendsList{
private FriendsListPK friendsListPK;
private User user;
private User friend;
private FriendsListStatus status;
@Embeddable
public static class FriendsListPK implements Serializable{
private Long userId;
private Long friendId;
private FriendsListPK(){
}
private FriendsListPK(Long userId, Long friendId){
this.userId = userId;
this.friendId = friendId;
}
@JoinColumn(name = "userid", referencedColumnName = "userid")
public Long getUserId(){
return this.userId;
}
public void setUserId(Long userId){
this.userId = userId;
}
@JoinColumn(name = "friendid", referencedColumnName = "userid")
public Long getFriendId(){
return this.friendId;
}
public void setFriendId(Long friendId){
this.friendId = friendId;
}
@Override
public boolean equals(Object o){
boolean ret = true;
if (o == null || this.getClass() != o.getClass()){
ret = false;
} else{
FriendsListPK that = (FriendsListPK) o;
ret = this.userId.equals(that.getUserId()) &&
this.friendId.equals(that.getFriendId());
}
return ret;
}
@Override
public int hashCode(){
return Objects.hash(this.userId, this.friendId);
}
}
/**
* Gets the value of friendsListPK
*
* @return the value of friendsListPK
*/
@EmbeddedId
public FriendsListPK getFriendsListPK() {
return this.friendsListPK;
}
/**
* Sets the value of friendsListPK
*
* @param argFriendsListPK Value to assign to this.friendsListPK
*/
public void setFriendsListPK(FriendsListPK argFriendsListPK) {
this.friendsListPK = argFriendsListPK;
}
/**
* Gets the value of status
*
* @return the value of status
*/
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "statusid", referencedColumnName = "statusid", nullable = false)
public FriendsListStatus getStatus() {
return this.status;
}
/**
* Sets the value of status
*
* @param argStatus Value to assign to this.status
*/
public void setStatus(FriendsListStatus argStatus) {
this.status = argStatus;
}
/**
* Gets the value of user
*
* @return the value of user
*/
@ManyToOne
@MapsId("userId")
public User getUser() {
return this.user;
}
/**
* Sets the value of user
*
* @param argUser Value to assign to this.user
*/
public void setUser(User argUser) {
this.user = argUser;
}
/**
* Gets the value of friend
*
* @return the value of friend
*/
@ManyToOne
@MapsId("friendId")
public User getFriend() {
return this.friend;
}
/**
* Sets the value of friend
*
* @param argFriend Value to assign to this.friend
*/
public void setFriend(User argFriend) {
this.friend = argFriend;
}
}
而我的用戶存儲庫就是這樣的:
@Repository
public interface UserDao extends JpaRepository<User, Long>{
public User findByEmail(String email);
}
每當我獲得一個用戶並嘗試通過getFriendsList()訪問其FriendsList時,它總是給我一個空集。 我已經嘗試過FetchType.EAGER以及Hibernate.Initialize並使用@Transactional和getFriendsList()。size()初始化舊方法。 我相信getFreindsList()的結果是HashSet而不是某種冬眠代理集的事實表明,冬眠甚至沒有嘗試延遲初始化它?
休眠生成的SQL如下:
select user0_.userid as userid1_11_, user0_.email as email2_11_, user0_.firstname as firstname3_11_, user0_.lastname as lastname4_11_, user0_.passwordhash as passwordhash5_11_, user0_.phone as phone6_11_ from usr user0_ where user0_.email =?;
select friendslis0_.user_userid as user_userid2_4_0_, friendslis0_.friend_userid as friend_userid1_4_0_, friendslis0_.friend_userid as friend_userid1_4_1_, friendslis0_.user_userid as user_userid2_4_1_, friendslis0_.statusid as statusid3_4_1_, user1_.userid as userid1_11_2_, user1_.email as email2_11_2_, user1_.firstname as firstname3_11_2_, user1_.lastname as lastname4_11_2_, user1_.passwordhash as passwordhash5_11_2_, user1_.phone as phone6_11_2_, friendslis2_.statusid as statusid1_5_3_, friendslis2_.statusname as statusname2_5_3_ from friendslist friendslis0_ inner join usr user1_ on friendslis0_.friend_userid=user1_.userid inner join friendsliststatus friendslis2_ on friendslis0_.statusid=friendslis2_.statusid where friendslis0_.user_userid=?;
select friendslis0_.user_userid as user_userid2_4_0_, friendslis0_.friend_userid as friend_userid1_4_0_, friendslis0_.friend_userid as friend_userid1_4_1_, friendslis0_.user_userid as user_userid2_4_1_, friendslis0_.statusid as statusid3_4_1_, user1_.userid as userid1_11_2_, user1_.email as email2_11_2_, user1_.firstname as firstname3_11_2_, user1_.lastname as lastname4_11_2_, user1_.passwordhash as passwordhash5_11_2_, user1_.phone as phone6_11_2_, friendslis2_.statusid as statusid1_5_3_, friendslis2_.statusname as statusname2_5_3_ from friendslist friendslis0_ inner join usr user1_ on friendslis0_.friend_userid=user1_.userid inner join friendsliststatus friendslis2_ on friendslis0_.statusid=friendslis2_.statusid where friendslis0_.user_userid=?;
如您所見,休眠IS確實是在嘗試查詢friendslist表,但是數據並沒有進入集合。 我與眾不同的唯一發現是,我們有2個相同的select語句進入了我們通常期望的1個好友列表中。也許第二個語句具有不同的用戶名,並且正在覆蓋第一個? 但是我不知道第二選擇來自何處。
這似乎是一個棘手的問題,我的解釋如下:
FiendsList
實體具有一個復合主鍵,該主鍵由userId
和friendId
列組成。 它們都引用User.userId
列:
@JoinColumn(name = "userid", referencedColumnName = "userid")
public Long getUserId(){
return this.userId;
}
@JoinColumn(name = "friendid", referencedColumnName = "userid")
public Long getFriendId(){
return this.friendId;
}
但是,在User實體上,您僅將映射放在FiendList.user
字段中:
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public Set<FriendsList> getFriendsList() {
return this.friendsList;
}
問題是休眠不足以讓休眠狀態知道要做什么,因為它需要兩列才能正確獲取FriendsList實體(因為它具有復合pk)。
您可能需要你一旦為了得到讓用戶實體執行附加查詢FriendList
通過將檢索到的User.userId
值作為的一部分FriendListPk
:
@Repository
public interface FriendListDao extends JpaRepository<FriendList, FriendListPK>{
... // use one of the find methods to get by pk.
}
糟糕,我很傻,原來我在二傳手中只是想念一個“ s”。
public void setFriendsList(Set<FriendsList> friendList) {
this.friendsList = friendsList;
}
實際上,“朋友列表”應該是“朋友列表”。 Hibernate正在獲取數據,但是當它試圖將其分配給字段時,現有的實例變量將被默默地分配給自己而不是分配器的參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.