我正在编写一个包含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%确定是否正确映射。
答案 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 。