NHibernate节省了数千件物品

时间:2011-10-06 15:29:20

标签: nhibernate nhibernate-mapping

我正在编写一个包含NHibernate的应用程序。

从我的初始配置开始,加载时间和所有内容似乎都在合理范围内。但是,我正在尝试为应用程序的更糟糕的情况场景执行压力测试。这种压力测试大大增加了物体的数量,现在我节省了3个等级:2400个交叉口,9600个区域和5000个车辆。

我遇到的问题是第一次尝试将项目保存到数据库中。我创建了所有项目,然后尝试通过以下方式保存它们:

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

但是,我一直在跑:

  

System.StackOverflowException未处理   消息:System.Data.dll中出现未处理的“System.StackOverflowException”类型异常

我尝试添加一个计数器,通过循环每2次迭代调用Flush。问题是车辆包含区域列表,区域包含车辆列表。事实恰恰相反,每辆车都有一个每个区域的清单,反之亦然。因此,呼叫第一个会话。保存不仅保存第一辆车,而且排队保存每个区域,从而节省所有车辆。

我将Vehicle中的Zone列表设置为inverse = false;因此,如果它们不存在,它将保存车辆列表中的所有区域。

有没有办法让NHibernate经常提交更改,所以我没有遇到StackOverflowException?我尝试在每10次保存中添加一个计数器来刷新会话,但是在达到此之前我遇到了溢出异常。当它保存第一辆车时,它会保存每个区域。由于每个区域都包含每辆车,因此可以节省每辆车。在我遇到溢出异常之前,我从来没有碰过冲洗。

我真的希望能够在车辆上调用保存并将保存级联到区域。从我不得不遍历区域列表,然后在保存车辆时再次修改区域,这将节省我很多时间。

有什么想法吗?

修改的 它似乎在tx.Commit()上窒息。任何帮助解决这个问题都将非常感激。

修改的 按要求发布映射。我删除了一些多余的属性和被映射的东西,并保留了主要类的3个列表。

车辆和交叉口来自设备,并按如下方式进行映射:

<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`">
    <joined-subclass name="EMTRAC.Intersections.Intersection, 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="all-delete-orphan" access="field" fetch="join" inverse="false">
          <key>
            <column name="Zone_PK" />
          </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>
    <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>

我在车辆方面将反转设置为true,因此希望它们都通过车辆进行映射,但不能100%确定是否正确映射。

2 个答案:

答案 0 :(得分:1)

它在tx.Commit()上窒息,因为这是运行真实数据库查询的地方。

如果您在区域和车辆之间存在适当的双向多对多关系,并且两侧都有级联,NHibernate应该妥善保管并正确保存所有内容。所以我假设你的问题是由大量实体和NHibernate试图绘制并保持整个对象图引起的。 Flushing在这里没有帮助,因为整个保存操作是由第一个对象保存时的级联执行的。

我担心您要么必须将保存操作拆分为先插入所有Zones空车辆集合,然后插入所有已分配区域的车辆,或者考虑使用NHibernate的StatelessSession这一整体操作。无状态会话不会将对象保留在任何缓存中,也不会执行级联 - 它通常更适合像您这样的批量更新。

答案 1 :(得分:1)

您可以尝试将您的区域逐步添加到您的车辆并保存它们。例如,你会做这样的事情:

Vehicle newVehicle = new Vehicle();

foreach(Zone newZone in myNewZonesList)
{
    using (var tx = session.BeginTransaction())
    {
        newVehicle.AddZone(newZone);
        session.SaveOrUpdate(newVehicle);
        tx.Commit();
    }
}

这种情况多久会发生一次?创建一辆新车并在跳街附近增加9600个区域是否常见?在某些时候,我认为你必须考虑 YAGNI