我已經研究過如何建立遞回關系并且我已經知道如何去做,但我無法避免這種關系的冗余。我有一個具有“朋友”屬性的用戶類。該用戶可以與許多其他用戶成為朋友,并且其他用戶可以與一個用戶成為朋友。所以我做了以下事情:
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "friends",
joinColumns = @JoinColumn(name = "user1_id"),
inverseJoinColumns = @JoinColumn(name = "user2_id"))
private List<User> friends = new ArrayList<User>();
要輸入資料,我使用以下服務功能。
public void addFriend(User requester, User requested) throws DataNotFoundException{
requester.getFriends().add(requested);
requested.getFriends().add(requester);
update(requested);
}
每次我更新“請求”時,它都會獲取與其“請求者”相關的物體并更新它。最初我以為是 Cascade 問題,但我看到 Cascade 默認是禁用的,所有選項都是將操作傳播給孩子的不同方式。
最后,這在我的表中創建了 2 行,其中包含冗余資料
user1_id | user2_id
1 2
2 1
我只想創建一條供關系雙方使用的線。
我考慮過為此創建一個自定義查詢,但從設計的角度來看,它似乎不是最合適的解決方案。因為它會創建一個我需要做的定制雪球。
編輯:當我從任一側洗掉 getFriends().add() 時,結果是相同的。代碼也似乎是多余的,因為我是第一次嘗試這種關系,我這樣做的方式與其他雙向多對多關系相同
uj5u.com熱心網友回復:
我認為這種行為是由于底層資料模型造成的。
每個人都User可以有 0...n 個朋友(又User是 s)。每次 aUser可以是有朋友的物體,也可以是其他人的朋友。每個User有朋友的人都存盤在 中user1_id,誰是朋友user2_id。
當 JPA 獲取用戶時,它總是使用相同的查詢來獲取朋友,如下所示:
select u2.* from user u
left join friends f on f.user1_id = u.id
left join user u2 on f.user2_id = u2.id
where u.id = ?;
JPA 無法區分是否應切換連接 - 因此需要插入“重復”行。
uj5u.com熱心網友回復:
重要的問題是:復制中的問題是什么?
我想說當前的變體是默認的正確建模方法。
替代方案可能是:
在寫入時,只填充一個方向,在資料庫端使用觸發器添加相反方向。這避免了將資料兩次傳輸到資料庫。只有在重新加載相關物體后才能看到反向方向,這通常意味著,只有在您使用新會話時。
寫作時,只填寫一個方向。將關系映射到一個視圖,該視圖在交換了兩個用戶 ID 的基礎表上執行聯合操作。您需要在該視圖上插入和洗掉觸發器。對您的應用程式的影響與變體 1 相同。
您可以建模
Friendship為其自己的物體,該物體Set<User>始終固定為具有兩個條目。如果這種關系對您的應用程式很重要,那么使用像 Neo4j 這樣的專用資料庫可能是值得的。它帶有自己的 Spring Data Neo4J。
uj5u.com熱心網友回復:
通過將彼此添加到彼此的朋友串列中,這根本不是多余的。
您映射的是單向關系。我認識我的朋友,但我的朋友不知道我認為他們是我的朋友。它只是更令人困惑,因為它是一個自我參考(用戶->用戶)。嘗試將其視為單獨的物件(父母-> 孩子),如果不是這樣,您將更容易理解您擁有什么以及您可能想要什么。
雖然你想要的似乎是正確的——我是你的朋友意味著你是我的——但它并不準確。我可以和那些不把我當作朋友的人交朋友——這確實是一種單向的關系。甚至您對請求者和被請求者的術語也意味著這種關系的另一面使其更像是跟隨/被關注者型別的情況。您的資料庫以及外鍵的性質反映了這一點。如果你得到了你想要的,關系表“朋友”將在“user1_id”中有一個用戶,并且可能在“user2_id”中有請求的 ID。當您查找被請求的朋友串列時(假設他們的 id 為“2”),請求不會顯示 - 資料庫將在“user1_id”值中搜索“2”但什么也找不到,
除非你添加requested.getFriends().add(requester);他們真的沒有朋友。
所以問題變成了這種關系對你的模型意味著什么。如果您不想僅僅因為比利在他的朋友串列中有約翰尼而自動強制約翰尼成為比利的朋友,但仍然需要一種方法來確定誰將約翰尼視為他們的朋友,請創建雙向關系:
@ManyToMany(mappedby="friends", fetch = FetchType.LAZY)
private List<User> friendedBy = new ArrayList<User>();
你的方法然后變成:
public void addFriend(User requester, User requested) throws DataNotFoundException{
requester.getFriends().add(requested);
requested.getFriendedBy().add(requester);
update(requested);
}
這為您提供了一種雙向遍歷關系的方法,并讓“被請求者”稍后決定他們是否真的想將請求者添加到他們自己的朋友串列中,而不是自動添加。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/477897.html
下一篇:如何修復org.hibernate.LazyInitializationException和org.hibernate.WrongClassException:使用faktorips
