6

我們有一個我們無法更改的遺留數據庫。我們正在嘗試移植到NHibernate,而不是舊的DataAccess層,這是一個垃圾,而且太慢了。將NHibernate導航器映射到組合鍵問題的一部分 - 遺留數據庫的使用

它具有這樣的表:

GPI表具有(PU_ID,PAR_ID,數據,數據2)個列
BLOCK表具有(GA_ID,數據PAR_ID)列
COMPANY表具有(PU_ID,數據)列

我創造了這些映射爲上面的表:

GPI

<class name="GroupPartnerInterest" table="[GPI]"> 
    <composite-id > 
     <key-property name="GroupId" column="PAR_ID" /> 
     <key-property name="CompanyId" column="PU_ID" /> 
    </composite-id> 
    <property name="data" column="Data"/> 
    <property name="data2" column="Data2"/> 
    <many-to-one name="Company" fetch="select" cascade="none"> 
     <column name="PU_ID"/> 
    </many-to-one> 
    <set name="Blocks" cascade="none" inverse="true" fetch="select"> 
     <key property-ref="GroupId"> 
      <column name="PAR_ID"/> 
     </key> 
     <one-to-many class="Block"/> 
    </set> 
</class> 

BLOCK

<class name="Block" table="[BLOCK]" > 
    <id name="BlockId" column="GA_ID" > 
     <generator class="assigned"/> 
    </id> 
    <property name="data" column="Data"/> 
    <property name="GroupId" column="PAR_ID"/> 
    <set name="GroupPartnerInterests" cascade="all-delete-orphan" fetch="select"> 
     <key property-ref="GroupId"> 
      <column name="PAR_ID"/> 
     </key> 
     <one-to-many class="GroupPartnerInterest"/> 
    </set> 
</class> 

公司

<class name="Company" table="[COMPANY]"> 
    <id name="CompanyId" column="PU_ID"> 
     <generator class="assigned"/> 
    </id> 
    <property name="data" column="Data"/> 
    <set name="GroupPartnerInterests" cascade="none" inverse="true" fetch="select"> 
     <key> 
      <column name="PU_ID"/> 
     </key> 
     <one-to-many class="GroupPartnerInterest"/> 
    </set> 
</class> 

的類是非常簡單樸素。全部實現Equals和GetHashCode方法。

這裏是工作的航海家列表:

  • GroupPartnerInterest.Company - 偉大工程
  • Company.GroupPartnerInterests - 偉大工程
  • GroupPartnerInterest.Company - 偉大工程

而且這兩個失敗:

  • Block.GroupPartnerInterests:

我有一個單元測試:

[TestMethod] 
public void TestGroupPartnerInterests() 
{ 
    using (ISession session = SessionFactory.OpenSession()) 
    { 
     IList<Block> blocks = session.CreateCriteria(typeof(Block)) 
      .SetMaxResults(5).List<Block>(); 

     foreach (var block in blocks) 
     { 
      TestContext.WriteLine("Block #{0}", block.BlockId); 

      if (block.GroupPartnerInterests != null) 
      { 
       foreach (GroupPartnerInterest gpi in block.GroupPartnerInterests) 
       { 
        TestContext.WriteLine("Company '{0}':", gpi.Company.CompanyId); 
       } 
      } 
     } 
    } 
} 

如果我註釋掉GPI映射測試工作模塊的導航地圖和輸出一些數據:

Block #1
Company 'LALA':
Company 'LALA SA':
Block #2
Company 'BG PO':
Company 'LIMPOPO':
Block #3
Company 'HAHA':
Company 'Other partner(s)':
Block #4

但測試失敗,出現以下錯誤:

NHibernate.LazyInitializationException: Initializing[Model.EntityClasses.Block#999]-failed to lazily initialize a collection of role: Model.EntityClasses.Block.GroupPartnerInterests, no session or session was closed.

'999'是現有的PAR_ID - 數據是一致的:在GPI中有兩個包含此PAR_ID和幾條記錄的塊。

爲什麼它在某個時候關閉會話?

  • GroupPartnerInterest.Blocks:

單元測試是如我上面提到的,只是不同的屬性用於幾乎相同。下面 錯誤是:

NHibernate.MappingException: NHibernate.MappingException: property not found: GroupId on entity Model.EntityClasses.GroupPartnerInterest.

如果我刪除「屬性-REF = GroupId的」從塊導航在GPI映射元素,我會出現以下情況例外:

NHibernate.FKUnmatchingColumnsException: NHibernate.FKUnmatchingColumnsException: Foreign key (FKA3966498349694F:[BLOCK] [PAR_ID])) must have same number of columns as the referenced primary key ([GPI] [PAR_ID, PU_ID]).

是有沒有辦法將Blocks映射到GPI,這樣GroupPartnerInterest.Blocks導航器就可以工作了?

謝謝, 亞歷克斯

回答

2

的問題如下:

  • 如果你有一個複合 ID的實體,它的所有引用必須 保持複合ID,所以 必須是兩個外鍵。
  • GroupPartnerInterest中的塊是一個集合,所以外鍵是Blocks,指向GroupPartnerInterest。這將需要兩個不可用的外鍵。
  • property-ref是用一些其他屬性替換主鍵。因此,它是該關係的一側的表的屬性,其爲GroupPartnerInterest,但不存在GroupId
  • 可以可能使用property-refGroupPartnerInterest.Blocks(因爲兩個外鍵被丟失,使Block.PAR_IDGPI.PAR_ID),但我會三思而後行。

我不能給你一個工作解決方案在這裏。我不使用組合鍵,這更復雜。但還有一些想法:

  • 我會盡量避免組合鍵。如果不可能,寫一個表示組合鍵的類。這使得它更容易處理。
  • 我會盡量避免不基於主鍵的關係。否則可能有其他原因,NH支持他們,我只是認爲他們會造成麻煩。

爲什麼會關閉?我不知道,我會看看堆棧跟蹤。它是從使用塊中真正拋出的異常?或者是從TestCleanup方法拋出?

+0

謝謝您的深入解答! 我將嘗試說服我們的團隊領導改變數據庫架構,只需添加一個自動生成(增量)主鍵到GPI表。 這將修復property-ref = GroupId問題,並應修復我的問題導航屬性 – LucID 2010-08-27 09:24:33

+0

我有一個非常類似的問題。我試圖用xml和流利的映射來映射這個場景,但沒有喜悅。不幸的是,我現在無法改變模式。我可以讓你看看嗎? http://stackoverflow.com/questions/25191275/fluent-nhibernate-map-hasmany-to-entity-table-with-no-primary-key – 2014-08-08 15:09:35