2011-11-26 123 views
2

我想用hibernate(在java中)實現一對多的關係。休眠:雙向一對多外鍵約束失敗

我有2個實體。

  • 實驗
  • ExperimentGroup

Experiment有很多ExperimentGroups。我試圖配置此一對多的關係,順便Hibernate官方文檔建議:http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/example-parentchild.html#example-parentchild-cascades

我的配置文件:

<class name="ExperimentImpl" table="Experiment"> 
    <id name="id" type="int" column="id"> 
     <generator class="increment" /> 
    </id> 
    <!-- One to Many --> 
    <set name="experimentGroups" table="ExperimentGroup" 
       lazy="false" fetch="select" cascade="all" inverse="true"> 
      <key> 
       <column name="Experiment_id" not-null="true" /> 
      </key> 
      <one-to-many class="ExperimentGroupImpl" /> 
    </set> 
</class> 
<class name="ExperimentGroupImpl" table="ExperimentGroup"> 
    <id name="id" type="int" column="id"> 
     <generator class="increment" /> 
    </id> 
    <many-to-one name="experiment" class="ExperimentImpl" fetch="select"> 
      <column name="Experiment_id" not-null="true" /> 
    </many-to-one> 
</class> 

添加新ExperimentGroupExperiment工作正常,但刪除實驗(和所有ExperimentGroups的)會導致異常:

不能刪除或更新父行:外鍵約束失敗 (testdbExperimentGroup,構造AINT FK9C71D86238B5500C FOREIGN KEY(Experiment_id)參考文獻Experimentid))

我ExperimentDAO代碼如下所示:

public void deleteExperiment(Experiment experiment) 
     throws DAOException 
    { 
     Session session = null; 
     Transaction t = null; 
     try{ 
      session = HibernateUtil.getSessionFactory().openSession(); 
      t = session.beginTransaction(); 
       session.delete(experiment); 
      t.commit(); 
      session.flush(); 
      session.close(); 
     }catch (HibernateException e) 
     { 
      e.printStackTrace(); 
      if (t != null) 
       t.rollback(); 

      if (session != null) 
       session.close(); 

      throw new DAOException(e, "Could not delete Experiment"); 
     } 
    } 

編輯: 的DAO代碼來創建一個實驗,ExperimentGroup

public Experiment createExperiment(String name, String description, RegisteredUser owner) 
{ 
    Transaction tx = null; 
    Session session = null; 
    try 
    { 
     session = HibernateUtil.getSessionFactory().openSession(); 

     tx= session.beginTransaction(); 
     ExperimentImpl e = new ExperimentImpl(); 

     e.setName(name); 
     e.setDescription(description); 
     e.setOwner(owner); 

     owner.getOwnedExperiments().add(e); 

     session.save(e); 
     tx.commit(); 
     session.flush(); 
     session.close(); 

     return e; 
    }catch (HibernateException ex) 
    { 
     if (tx != null) 
      tx.rollback(); 

     if (session!=null) 
      session.close(); 

     throw ex; 
    } 
} 




public ExperimentGroup createAndAddExperimentGroup(Experiment experiment, String experimentGroupName, Date startDate, Date endDate) throws ArgumentException 
    { 

     Transaction t = null; 
     Session session = null; 

     try 
     { 
      session = HibernateUtil.getSessionFactory().openSession(); 
      t = session.beginTransaction(); 
       ExperimentGroupImpl g = new ExperimentGroupImpl(); 
       g.setEndDate(endDate); 
       g.setStartDate(startDate); 
       g.setName(experimentGroupName); 
       g.setExperiment(experiment); 

       experiment.getExperimentGroups().add(g); 
       g.setExperiment(experiment); 

       session.save(g); 
       session.update(experiment); 
      t.commit(); 
      session.flush(); 
      session.close(); 

      return g; 

     }catch(HibernateException e) 
     { 
      if (t!=null) 
       t.rollback(); 

      if (session!= null) 
       session.close(); 

      throw e; 
     } 
    } 

有一個對於實驗的其他屬性,比如我從配置文件中刪除的名稱,描述等,因爲它們對一對多關係沒有影響。

有什麼建議嗎?我錯了什麼?

+0

錯誤提示休眠試圖刪除父Experimient實體而不先刪除所有ExperimentGroups。您可以發佈構建實驗/實驗組實體的代碼嗎? –

+0

嗨,謝謝你的回答。我把代碼放在「問題」(上面)中。 – sockeqwe

+0

@sockeqwe:你有外鍵約束的ON DELETE CASCADE子句嗎?如果不是,那麼情況很明顯:當你嘗試刪除父實體並且Hibernate遵循一對多關聯時,Hibernate首先刪除子實體,然後刪除父實體。如果Hibernate不知道這個關聯,那麼刪除父實體並不會導致刪除子項,這會導致違反約束。我不清楚,爲什麼你提供了'RegisteredUser'實體的代碼示例... –

回答

0

我的印象是,您試圖刪除手動創建的分離實體。我會嘗試實際刪除它之前使用你要刪除的實驗和負載的主鍵:

session = HibernateUtil.getSessionFactory().openSession(); 
t = session.beginTransaction(); 
ExperimentImpl persistentExperiment = session.load(ExperimentImpl.class, experiment.getId()); 
session.delete(persistentExperiment); 
t.commit(); 
+0

噢,謝謝解決了這個問題... 我認爲休眠負責將實體附加到新會話... 什麼是在應用程序層與我的Experiment對象保持同步的正常方式? Hibernate.merge()? – sockeqwe