從我之前的問題來看。Hibernate: Cannot fetch data back to Map<>, 我在嘗試取回資料后得到了NullPointerException。我認為原因是主鍵(當作為put(K,V)添加到Map時,主鍵是空的,但在JPA持久化之后,它創建了主鍵,從而改變了HashMap())。我有這個equals和hashCode:
User.java:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (! (o instanceof User) return false。
User user = (User) o;
return Objects.equals(id, user. id) && Objects. equals(username, user.username) && Objects. equals(about, user.about) && Objects.equals(friendships, user. friendships) && Objects.equals(post, user.posts) 。
}
@Override; }
public int hashCode() {
return Objects.hash(id, username, about, friendships, posts)。
}
-> 我在計算hash時使用了所有欄位。這使得NullPointerException BUT不是因為id(主鍵),而是因為hash中涉及的集合(friends和posts)。因此,我改變了這兩個函式,以使用僅資料庫的平等性:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (id == null) return false;
if (! (o instanceof User)) return false;
User user = (User) o;
return this.id.equals(user.getId() );
}
@Override
public int hashCode() {
return id == null ? System.identityHashCode(this) :
id.hashCode()。
所以現在只有id欄位參與了哈希。現在,它沒有給我獲取的資料帶來NullPointerException。我使用這段代碼來測驗它:
(from id)
(來自User.java): DemoApplication.java: 你可以看到我是 但即使如此,我還是得到了正確的元素。輸出: 你可以看到: uj5u.com熱心網友回復: 并不是所有的Map實作都使用hashCode(例如TreeMap的實作就不使用hashCode,而是使用比較器來將條目排序到樹中)。
所以我首先會檢查hibernate是否替換了該欄位: 有自己的Map的實作。 那么,即使hibernate保留了HashMap,而物件的哈希碼發生了變化,你可能會很幸運,新舊哈希碼都給出了相同的哈希圖桶。
由于物件是相同的(hibernate會話保證了這一點),用于在桶中查找物件的等價物將發揮作用。(如果桶中有超過8個元素,那么桶就不是一個鏈接串列,而是一個按哈希碼排序的B樹,在這種情況下,它不會找到你的條目,但地圖似乎只有2-3個元素,所以不可能是這種情況)。
uj5u.com熱心網友回復: 現在我明白了你的問題。
看看地圖檔案,我們讀到以下內容:public void addFriend(user friend){
Friendship friendship = new Friendship() 。
friendship.setOwner(this)。
friendship.setFriend(friend) 。
this.friendships.put(friend, friendship);
@Bean
public CommandLineRunner dataLoader(UserRepository userRepo, FriendshipRepository friendshipRepo){
return new CommandLineRunner() {
@Override
public void run(String... args) throws Exception{
User f1 = new keyword">new User("friend1") 。
User f2 = new User("friend2") 。
User u1 = new User("user1") 。
System.out.println(f1)。
System.out.println(f1.hashCode())。
u1.addFriend(f1)。
u1.addFriend(f2);
userRepo.save(u1)。
User fetchedUser = userRepo.findByUsername("user1")。
System.out.println(fetchedUser.getFriendships().get(f1).getFriend() )。
System.out.println(fetchedUser.getFriendships().get(f1).getFriend().hashCode() )。
}
};
}
把f1用戶放入user1(友誼的所有者)的友誼中。當f1.getId() == nulluser1。當f1 id被Hibernate分配其主鍵值的時候(因為友誼關系是Cascade.All,所以包括持久化)get從Map中取回f1用戶,它用hashCode進行查找,現在它被破壞了,因為f1.getId() != null。User{id=null, username='friend1'/span>, about='null'/span>, friendships={}, posts=[]}。
-935581894
...
用戶{id=3, username='friend1', about='null', friendships={}, posts={}}.
3
id是空的,然后是3,hashCode是-935581894,然后是3。那么,我怎么可能得到正確的元素呢?
private Map< User, Friendship> friendships = new HashMap<>()。
這看起來并沒有明確的答案,正如 @Thierry 所說,你似乎只是運氣好。關鍵是 "不要使用易變的物件作為地圖鍵"。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/309828.html
標籤:
