2010-06-29 34 views
1

好吧,所以我有一點問題,我的Hibernate映射,並獲得所需的行爲。如何停止嘗試更新一對多過度連接表的休眠表

基本上我有如下Hibernate映射:

<hibernate-mapping> 
    <class name="com.package.Person" table="PERSON" schema="MYSCHEMA" lazy="false"> 
     <id name="personId" column="PERSON_ID" type="java.lang.Long"> 
      <generator class="sequence"> 
       <param name="sequence">PERSON_ID_SEQ</param> 
      </generator> 
     </id> 

     <property name="firstName" type="string" column="FIRST_NAME"> 
     <property name="lastName" type="string" column="LAST_NAME"> 
     <property name="age" type="int" column="AGE"> 

     <set name="skills" table="PERSON_SKILL" cascade="all-delete-orphan"> 
      <key> 
       <column name="PERSON_ID" precision="12" scale="0" not-null="true"/> 
      </key> 
      <many-to-many column="SKILL_ID" unique="true" class="com.package.Skill"/> 
     </set> 
    </class> 
</hibernate-mapping> 


<hibernate-mapping> 
    <class name="com.package.Skill" table="SKILL" schema="MYSCHEMA"> 
     <id name="skillId" column="SKILL_ID" type="java.lang.Long"> 
      <generator class="sequence"> 
       <param name="sequence">SKILL_ID_SEQ</param> 
      </generator> 
     </id> 
     <property name="description" type="string" column="DESCRIPTION"> 
    </class> 
</hibernate-mapping> 

所以讓我們假設我已經填充技能表,在它的一些技巧。現在,當我創建一個新人時,我想通過設置技能ID來將他們與技能表中已經存在的一組技能相關聯。例如:

Person p = new Person(); 
p.setFirstName("John"); 
p.setLastName("Doe"); 
p.setAge(55); 

//Skill with id=2 is already in the skill table 
Skill s = new Skill() 
s.setSkillId(2L); 

p.setSkills(new HashSet<Skill>(Arrays.asList(s))); 
PersonDao.saveOrUpdate(p); 

如果我嘗試這樣做,但我得到一個錯誤說:

WARN (org.slf4j.impl.JCLLoggerAdapter:357) - SQL Error: 1407, SQLState: 72000 
ERROR (org.slf4j.impl.JCLLoggerAdapter:454) - ORA-01407: cannot update ("MYSCHEMA"."SKILL"."DESCRIPTION") to NULL 

ERROR (org.slf4j.impl.JCLLoggerAdapter:532) - Could not synchronize database state with session 
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update 

的原因,我得到這個錯誤,我認爲是因爲Hibernate看到與ID爲2的技術已'更新'其描述爲空(因爲我從來沒有設置它)並嘗試更新它。但我不希望Hibernate更新它。我想要的是插入新的Person p,並將一條記錄插入連接表PERSON_SKILL中,該連接表匹配p與SKILL表中的技能(ID = 2),而不觸及SKILL表。

有沒有辦法實現這種行爲?

回答

1

而不是創造技能的對象自己:

//Skill with id=2 is already in the skill table 
Skill s = new Skill() 
s.setSkillId(2L); 
p.setSkills(new HashSet<Skill>(Arrays.asList(s))); 

您應該從Hibernate的Session來獲取它:

Skill s = (Skill) session.get(Skill.class, 2L); 
p.setSkills(new HashSet<Skill>(Arrays.asList(s))); 

通過這種方式,會議認爲,包含在p.skills技能是persistent, and not transient

+0

技能不是瞬態的(這會導致插入),它具有數據庫中的表示形式,它具有標識符值。 – 2010-06-29 16:58:25

+0

那麼它會標記什麼 - 「分離」?我認爲解決方案是一樣的。 – 2010-06-29 17:06:04

+0

是的,它是分離的。 – 2010-06-29 17:25:59

1

這可能是如果你不級聯all-delete-orphan這是明確告訴休眠級聯的變化。

但正確的做法是IMO從數據庫中加載所需的Skill實體,並將其添加到Person的一組技能中。

+0

好吧,刪除全部刪除孤兒的工作,但這裏被認爲是最佳做法?先檢索技能並將其與我的人員關聯或刪除級聯屬性? – 2010-06-29 17:19:47

+0

嗯,我還是希望從某些情況下級聯中獲益,級聯什麼都不是好的解決方案:)所以我會先從數據庫中加載技能。 – 2010-06-29 17:29:06