2011-10-05 148 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万更好。

但是我想指出,这不是一个小样本量的主要问题。这只是每个人都需要考虑的事情。

希望这有助于任何人绊倒这一点。