2个列表的NHibernate双向多对多映射

2个列表的NHibernate双向多对多映射,nhibernate,nhibernate-mapping,Nhibernate,Nhibernate Mapping,我正在尝试为两个类生成正确的映射,这两个类中有彼此的集合 我目前有一个区域和一个车辆等级。Zone类包含包含该分区的车辆列表。车辆类别包含包含车辆的区域列表。正如您所看到的,这两个列表彼此直接相关。但是,当试图保存一个对象时,映射不断给我一个外键约束错误 有人能解释一下我做错了什么吗 以下是车辆类别的映射: <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> <class xmlns="urn:nhibernate-

我正在尝试为两个类生成正确的映射,这两个类中有彼此的集合

我目前有一个区域和一个车辆等级。Zone类包含包含该分区的车辆列表。车辆类别包含包含车辆的区域列表。正如您所看到的,这两个列表彼此直接相关。但是,当试图保存一个对象时,映射不断给我一个外键约束错误

有人能解释一下我做错了什么吗

以下是车辆类别的映射:

<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>
之后,我将区域添加到车辆列表中,并将车辆添加到区域列表中,然后尝试通过以下方式保存列表:

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();
    }

}

此时提交调用抛出外键约束异常。我做错了什么?

好吧,我终于明白我做错了什么。我最终确定的映射版本是:

车辆:

    <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>
如果两个列表中有大量的类

原因是,在调用提交之前,事务将锁定数据库中的项。一旦调用提交,所有更新和排队的所有内容都将实际执行。因此,save只是将实际事务发送到数据库,以便在调用commit后发出。提交本身是进行所有实际工作的地方,一旦它被调用,实际的项目就会存储在数据库中。很明显,您不希望交易花费非常长的时间

就我而言,我试图拯救5000辆汽车和9600个区域。这将导致负责存储包含4800万行的两个列表的表结束,因此需要为每辆车创建一个单独的事务和提交调用。使用这种方法可以防止这些项目在4800万次插入的整个过程中被锁定,而且效率更高。相反,保存每辆车后会调用commit,因此除了保存的第一辆车(因为第一次保存必须保存所有区域,如果它们不存在的话),每个事务只会发出9600个命令。这显然比4800万强得多

然而,我想指出的是,在样本量小得多的情况下,这并不是一个主要问题。这只是每个人都要考虑的事情

希望这能帮助那些偶然发现这一点的人

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();
    }

}
    <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>
foreach (Vehicle veh in Program.data.Vehicles.list)
{
    using (ITransaction tx = session.BeginTransaction())
    {
        session.Save(veh);

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