2013-01-09 27 views
3

我有兩個實體Person和Preference。兩者之間有很多很多的關係。 人和偏好關係存儲在一個映射表在休眠狀態下重新排列列表中的項目many-many association

CREATE TABLE `person_2_preference` (
`person_id` varchar(32) NOT NULL, 
`preference_id` varchar(32) NOT NULL, 
`sort_order` int(11) NOT NULL, 
PRIMARY KEY (`person_id`,`preference_id`); 

一個人有喜好的有序列表,如下圖所示。

<list name="preferences" table="person_2_preference" lazy="true" inverse="false" 
     cascade="save-update"> 
      <key column="person_id" update="false"/> 
      <index column="sort_order"/> 
      <many-to-many class="com.xx.Preference" column="preference_id" /> 
     </list> 

在Java類中,我想重新排序在某些情況下,喜好,所以我做了Collections.swap像 Collections.swap(person.getPreferences(),指數,指數++)(我有驗證,以確保指數不超出範圍)

當我保存人 - personDao.saveOrUpdate(人),我得到一個唯一的約束違反異常,因爲主鍵。

我有其他有序的關係是一對多的,使用Collections.swap的重新排序很有效。這是對多關係的限制嗎?感謝您的時間

回答

1

我認爲這個問題來自Hibernate的內部存儲結構,它會讓你的交換感到困惑。 Hibernate還將列表中的對象存儲在第一級緩存中,並且在某處存儲了實際存儲在數據庫中的值,以便可以決定是否需要更新。

當您更改列表中的順序時,有兩種方法可以更新:或者讓person_id和preference_id保持不變並修改sort_order,或者讓sort_order保持不變並修改person_id和preference_id。在交換的情況下,第二種方式在兩次更新中的第一次之後導致唯一的約束違反。由於某些原因,這與Hibernate的內部組織有關,Hibernate以第二種方式進行更新。

有(至少)三種不同的可能性,如何來解決這個問題:

  1. 你加一個串行表person_2_preference,使該系列的主鍵(休眠愛主鍵,只有一個單柱)。我沒有測試這個,我不是100%確定它是否能解決你的問題。

  2. 您在HQL UPDATE語句手動完成更新:

    UPDATE Person2Preference SET sortOrder= :order WHERE personId=:person and preferenceId=:preference

    Person2Perference是映射到person_2_preference類。這必須爲每個孩子對象完成。在此之後,父對象和/或子對象的evict()可能是可推薦的(Hibernate在此更新之後不更新第一級緩存)。

  3. 由於Hibernate的結果,您不會交換列表中的元素。您將此列表複製到數組列表(或數組)中,並僅在副本中進行交換。這不需要太多內存,因爲在你的副本中只有對象的引用。在Hibernate對象中,你只需要更新排序順序。

我可能會做解決方案3.解決方案1我會做,如果有任何其他需要新的序列。

+0

感謝您的迴應,我不需要做#2有效的做#3?因爲要更新sort_order我需要映射到映射表的類。我試圖避免將一個類映射到這個many2many表,因爲該表沒有任何其他列 – Gowtham

+0

您不需要#2做#3。在#2中使用HQL更新語句,在#3中只更新父對象,即i。即'Person'實例。但是你是對的,對於#2和#3(甚至#1)你都需要一個映射到person_2_preference表的類。我以爲你已經有過這樣的課。不過,我會介紹這門課,因爲它爲您提供了在這裏需要的靈活性。創建這個簡單的類沒有太多的工作。 – Johanna

+0

我有同樣的問題,並解決方案(1)修復它。謝謝! –