2011-10-05 58 views
0

我試圖爲2個類生成正確的映射,它們之間有彼此的集合。NHibernate雙向多對多映射的2個列表

我目前有一個Zone和一個Vehicle類。 Zone類包含一個包含區域的車輛列表。 Vehicle類包含一個包含車輛的區域列表。正如你所看到的,這兩個列表直接相關。但是,當我試圖保存我的一個對象時,映射不斷給我一個外鍵約束錯誤。

有人可以解釋我做錯了什麼嗎?

下面是汽車類的映射:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 
    <class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Devices.Device, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Device`"> 
    <id name="PK" type="System.Int64, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="PK" /> 
     <generator class="identity" /> 
    </id> 
    <version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" /> 
    <joined-subclass name="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> 
     <key> 
     <column name="Device_id" /> 
     </key>  
     <component name="Zones" access="property"> 
     <bag name="_list" cascade="save-update" access="field" table="VehicleZones"> 
      <key> 
      <column name="Veh_id"/> 
      </key>   
      <many-to-many class="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </bag> 
     </component> 
     <property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ID" /> 
     </property>  
    </joined-subclass> 
    </class> 
</hibernate-mapping> 

這裏是我的區類的映射:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 
    <class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Zone`"> 
    <id name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="PK"/> 
     <generator class="identity" /> 
    </id> 
    <version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" /> 
    <property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ID" /> 
    </property>  
    <component name="Vehicles" access="property"> 
     <bag name="_list" cascade="save-update" access="field" table="VehicleZones" inverse="true"> 
     <key> 
      <column name="Zone_id" not-null="false"/> 
     </key> 
     <many-to-many class="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </bag> 
    </component> 
    </class> 
</hibernate-mapping> 

我通過保存的區域和車輛:

using (var session = _sessionFactory.OpenSession()) 
{ 
    foreach (Zone zone in Program.data.Zones.list) 
    { 
     session.SaveOrUpdate(zone); 
    } 
    foreach (Vehicle veh in Program.data.Vehicles.list) 
    { 
     session.SaveOrUpdate(veh); 
    } 
} 

之後,我將區域添加到車輛列表和車輛到區域列表,然後我嘗試通過以下方式保存列表:

using (var session = _sessionFactory.OpenSession()) 
{    
    foreach (Zone zone in Program.data.Zones.list) 
    { 
     foreach (Vehicle veh in Program.data.Vehicles.list) 
     { 
      veh.Zones.Add(zone); 
      zone.Vehicles.Add(veh); 
     } 
    } 

    using (var tx = session.BeginTransaction()) 
    { 
     foreach (Vehicle veh in Program.data.Vehicles.list) 
     { 
      session.Update(veh.Zones); 
     } 
     tx.Commit(); 
    } 

} 

此時Commit調用引發外鍵約束異常。我究竟做錯了什麼?

回答

0

好的,我終於弄清楚我做錯了什麼。我完成了映射的版本是:

車輛:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 
    <class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Devices.Device, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Device`"> 
    <id name="PK" type="System.Int64, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="PK" /> 
     <generator class="identity" /> 
    </id> 
    <version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" />  
    <joined-subclass name="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> 
     <key> 
     <column name="Device_id" /> 
     </key>  
     <component name="Zones" access="property"> 
     <bag name="_list" cascade="save-update" access="field" table="VehicleZones" inverse="true"> 
      <key> 
      <column name="veh_id" not-null="true"/> 
      </key> 
      <many-to-many class="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </bag> 
     </component> 
     <property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ID" /> 
     </property>  
    </joined-subclass> 
    </class> 
</hibernate-mapping> 

區:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 
    <class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Zone`"> 
    <id name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="PK"/> 
     <generator class="identity" /> 
    </id> 
    <version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" /> 
    <property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="ID" /> 
    </property> 
    <component name="Vehicles" access="property"> 
     <bag name="_list" cascade="save-update" access="field" table="VehicleZones"> 
     <key> 
      <column name="veh_id" not-null="true"/> 
     </key> 
     <many-to-many class="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </bag> 
    </component> 
    </class> 
</hibernate-mapping> 

他們最主要的是造成了我所有的我的問題是=「真」被設置在逆區域映射方面。

如果你注意到我從Zone側移除了這個標誌並將它放在了Vehicle端。這個標誌通知Hibernate哪個類負責維護關係。我正在保存車輛,而不是導致處理外鍵錯誤的區域。

因爲我確實希望車輛負責保存這種關係,所以我需要在車輛側面將反向設置爲真。我還需要將級聯標記爲「save-update」,以便車輛將更新級聯到區域並將關係鏈接到區域。因此,保存單個車輛將表中的區域連接起來,並保存區域對象,從而有效地解決了之前在保存過程中遇到的錯誤。

現在節能工作正常。如果你有兩個列出了大量的類

foreach (Vehicle veh in Program.data.Vehicles.list) 
{ 
    using (ITransaction tx = session.BeginTransaction()) 
    { 
     session.Save(veh); 

     // Commit transactions 
     tx.Commit(); 
    } 
} 

:雖然我建議的方法對節約沿線的這些項目。

原因是您的交易將在您調用提交期間鎖定數據庫中的項目。一旦提交被調用,所有更新和排隊的所有內容都會實際執行。因此,保存僅僅是在調用提交後將實際事務發送到數據庫。提交本身就是所有實際工作發生的地方,一旦被調用,實際的項目被存儲在數據庫中。很顯然,你不希望交易花費很長時間。

在我的情況下,我試圖節省5000輛車和9600個區域。這將最終由負責存儲包含4800萬行的兩個列表的表格負責,因此爲每輛車創建單獨的事務和提交調用的原因。使用這種方法可以防止這些項目在整個4800萬個插入過程中被鎖定,並且效率更高。相反,在保存每輛車之後調用提交,因此除了保存第一輛車以外(因爲第一次保存必須保存所有區以及不存在),所以每個車只會發出9600個命令交易。這顯然比4800萬更好。

但是我想指出,這不是一個小樣本量的主要問題。這只是每個人都需要考慮的事情。

希望這有助於任何人絆倒這一點。