擁有這個物體:
User.java:
@Entity
@Data @Entity
@NoArgsConstructor
public class User {
@Id @GeneratedValue
private int id;
private String username;
private String about;
@OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Map<User, Friendship> friendships = new HashMap<>()。
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Collection<Post> posts = new ArrayList<> ()。
public User(String username){
this.username = username;
}
public void addFriend(User friend){
Friendship friendship = new Friendship() 。
friendship.setOwner(this)。
friendship.setFriend(friend)。
this.friendships.put(friend, friendship)。
}
public void addPost(Post post){
post.setAuthor(this)。
this.post.add(post)。
}
Friendship.java:
@Entity
@Getter
@Setter
@NoArgsConstructor @NoArgsConstructor
public class Friendship {
@EmbeddedId[/span
private FriendshipId key = new FriendshipId()。
private String level;
@ManyToOne
@MapsId("ownerId")
private 用戶所有者。
@ManyToOne
@MapsId("friendId")
private User friend。
}
FriendshipId.java:
@Embeddable。
public class FriendshipId implements Serializable {
private int ownerId;
private int friendId;
UserRepository.java:
public interface UserRepository extends JpaRepository< User, Integer> {
public User findByUsername(String username)。
最后DemoApplication.java:
@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") 。
u1.addFriend(f1)。
u1.addFriend(f2);
userRepo.save(u1)。
User fetchedUser = userRepo.findByUsername("user1")。
System.out.println(fetchedUser);
System.out.println(fetchedUser.getFriendships().get(f1))。
}
};
}
在userRepo.save(u1)操作之后,表格的內容如下:
mysql> select * from user;
---- ------- ----------
| id | about | username |
---- ------- ----------
| 1 | NULL | user1 !
| 2 | NULL | friend1 !
| 3 | NULL | friend2 !
---- ------- ----------
select * from friendship;
------- ----------- ---------- -----------------
| 級別 | 朋友_id | 業主_id | 友誼_key !
------- ----------- ---------- -----------------
| NULL | 2 | 1 | 2 !
| NULL | 3 | 1 | 3 !
------- ----------- ---------- -----------------
如你所見,所有的朋友都被保存了。然而這個宣告:
System.out.println(fetchedUser.getFriendships().get(f1))。
回傳null。即使fetchedUser有取來的朋友的地圖:
System.out.println(fetchedUser)。
列印:
User(id=1, username=user1, about=null, friendships={User(id=2, username=friend1, about=null, friendships={}, posts=[])=com. example.demo.model.Friendship@152581e8, User(id=3, username=friend2, about=null, friendships={}, posts=[])=com.example.demo.model.Friendship@58a5d38 }, posts=[] )
那么,為什么朋友f1不能被獲取(更確切地說,是null),而地圖friendships被完全獲取(所有的朋友都被獲取了,你可以從上面的陳述句看到)?
PS:
我已經洗掉了@Data lombok注解(只是添加了@Getter,@Setter和@NoArgsConstrutor`)并自己重寫了equalsAndHashCode:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (! (o instanceof User) return false;
User user = (User)o;
return id == user.id && Objects.eals(username, user. && Objects.equals(about, user.about) && Objects.equals(friendships, user.friendships) && Objects.equals(post, user.post) 。)
}
@Override
public int hashCode() {
return Objects.hash(id, username, about, friendships, posts)。
或者換句話說,equals()方法使用User類的所有欄位。
uj5u.com熱心網友回復:
如你所見,所有的朋友都被保存了。然而這個宣告:
System.out.println(fetchedUser.getFriendships().get(f1)); returns null.即使fetchedUser有Map of friends 取出:
System.out.println(fetchedUser)。列印:
User(id=1, username=user1, about=null, friendships={User(id=2, username=friend1, about=null, friendships={}, posts=[])=com. example.demo.model.Friendship@152581e8, User(id=3, username=friend2, about=null, friendships={}, posts=[])=com.example.demo.model.Friendship@58a5d38 }, posts=[] )
問題是,當f1 User被添加到friendships HashMap時,主鍵id沒有出現。它后來被Hibernate在某些時候更新。這就改變了HashCode的值!!!
hashcode
hashcode鍵的值在被添加到Map后不應該被改變。這就造成了這個問題。簡單的測驗代碼來模擬這個問題 - https://www.jdoodle.com/a/3Bg3
import lombok.*;
import java.util.*;
public class MyClass {
public static void main(String args[]){
Map<User, String> friendships = new HashMap<>()。
User f1 = new User() 。
f1.setUsername("friend1")。
User f2 = new User();
f2.setUsername("friend2")。
friendships.put(f1, "我被改變了,找不到我")。
friendships.put(f2, "沒有變化。 所以,你找到我了")。
System.out.println(f1.hashCode()); // -600090900[/span
f1.setId(1); // 某個id被hibernate分配。打破了哈希代碼
System.out.println(f1.hashCode()); // -600090841 (this changed!!)
System.out.println(friendships); //列印f1、f2都是。
System.out.println(friendships.get(f1)); //列印null。
System.out.println(friendships.get(f2))。
}
}
// @Data
@Getter
@Setter
@EqualsAndHashCode[/span]@ToString[/span
class Use
{
private int id;
private String username;
解決方案
在用戶被添加到地圖后,hashcode的值不應該被改變。我認為有幾個選項可以用來解決這個問題--
- 在資料庫中的朋友被放入
friendship地圖之前,先把它保存在資料庫中。所以那個id已經被分配了。 - 完全不要覆寫
equals和hashcode。用默認值作業。基于,物件的身份。 - 使用一個固定的哈希碼。例如,如果
username被分配后從未改變,這個欄位可以用來生成hashcode值。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/309837.html
標籤:
