2011-10-06 64 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()的時間越來越長? –