2011-10-06 62 views
1

我正在编写一个合并了NHibernate的应用程序。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了未处理 消息:类型系统的”未处理的异常。 StackOverflowException'发生在System.Data.dll中

我曾尝试添加一个计数器,每循环2次循环调用Flush。问题在于车辆包含区域列表,区域包含车辆列表。恰巧每辆车都有一个每个区域的清单,反之亦然。所以召唤第一次会议.Save不仅拯救了第一辆汽车,而且还保存了每个区域,从而节省了所有车辆。

我在汽车的区域列表设置为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%确定是否映射正确。

+0

每辆车都有一个每个区域的列表,反之亦然?这种关系的重点是什么?这将是一个链接表(#vehicles * #zones)行。 – dotjoe

+0

这被设计成压力测试的方式。并非所有生产的车辆都必须拥有每个区域等。但车辆和区域的链接始终是双向的。我只是用它作为在更糟情况下强调的参考。我想看看NHibernate是否可以处理大量的对象集合。同时一次保存这些项目很少,如果以这种方式完成的话,但是如果需要出现或者使用NHibernate没有意义,我必须使用它。 –

+1

哦,我明白了,当然只有多对多的一方应该级联?你能发布映射吗? – dotjoe

回答

1

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

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

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

+0

我不认为你可以通过无状态会话保存集合? –

+1

啊,你说得对。它可以与双向一对多的工作,但不知道多对多是可能的。所以我除了手动迭代之外别无他法。 – NOtherDev

+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

+0

创建车辆并向其添加所有区域可能是一种相对经常发生的方法。创建区域并将其添加到所有车辆也是如此。如果不是所有的区域都是他们中的绝大多数。但是,你只做一次迭代,而不是每一个区域的每一辆车,这是我必须做的压力测试,这是我现在遇到的问题。 –

+0

使用每次保存的交易方法似乎有助于到目前为止。以后我会知道它是否成功完成。我做了数学计算,结果表明它将在映射2个列表的表中有4800万行。对于单个交易来说这有点矫枉过正,可以解释为什么它会死亡。话虽如此,我将不得不等待所有4800万条记录插入此案例中,以了解这次保存是否完成。与此同时,迄今为止的建议+1。 –

+0

为什么每次调用tx.Commit()的时间越来越长? –