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