NHibernate导航器映射到复合键问题的一部分 - 遗留数据库使用

Luc*_*cID 6 nhibernate nhibernate-mapping legacy-database composite-id

我们有一个我们无法改变的遗留数据库.我们正试图转移到NHibernate而不是旧的DataAccess层,这是一个垃圾,而且速度太慢.

它有这样的表:

GPI表有(PU_ID,PAR_ID,Data,Data2)列
BLOCK表有(GA_ID,Data,PAR_ID)列
COMPANY表有(PU_ID,Data)列

我为上面的表创建了这些映射:

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>
Run Code Online (Sandbox Code Playgroud)

<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>
Run Code Online (Sandbox Code Playgroud)

公司

<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>
Run Code Online (Sandbox Code Playgroud)

这些课程非常简单明了.全部实现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 );
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我注释掉GPI映射测试中的块导航映射并输出一些数据:

Block#1
公司'LALA':
公司'LALA SA':
Block#2
公司'BG PO':
公司'LIMPOPO':
Block#3
公司'HAHA':
公司'其他合作伙伴':
Block#4

但是测试失败并出现以下错误:

NHibernate.LazyInitializationException:正在初始化[Model.EntityClasses.Block#999] - 无法初始化角色集合:Model.EntityClasses.Block.GroupPartnerInterests,没有关闭会话或会话.

'999'是现有的PAR_ID - 数据是一致的:这个PAR_ID有两个块,GPI有几个记录.

为什么它在某个时候关闭会话?

  • GroupPartnerInterest.Blocks:

单元测试与我上面提到的几乎相同,只是使用了不同的属性.错误如下:

NHibernate.MappingException:NHibernate.MappingException:找不到属性:实体Model.EntityClasses.GroupPartnerInterest上的GroupId.

如果我从GPI映射中的Blocks导航器元素中删除"property-ref = GroupId",我将得到以下异常:

NHibernate.FKUnmatchingColumnsException:NHibernate.FKUnmatchingColumnsException:外键(FKA3966498349694F:[BLOCK] [PAR_ID]))必须与引用的主键([GPI] [PAR_ID,PU_ID])具有相同的列数.

有没有办法将块映射到GPI,以便GroupPartnerInterest.Blocks导航器可以工作?

谢谢,亚历克斯

Ste*_*ger 2

问题如下:

  • 如果您有一个具有复合 id 的实体,则对其的所有引用都必须维护复合 id,因此必须有两个外键。
  • 块 inGroupPartnerInterest是一个集合,因此外键位于 in Blocks,指向GroupPartnerInterest。它需要两个外键,但目前不可用。
  • property-ref就是用其他属性替换主键。因此,它是关系一侧表的属性,即GroupPartnerInterest,但不存在GroupId
  • 您可能可以使用property-reffor GroupPartnerInterest.Blocks(因为缺少两个外键,以表明Block.PAR_IDGPI.PAR_ID,但我会三思而后行。

我在这里无法给你一个可行的解决方案。我不使用复合键,这更复杂。但还有一些想法:

  • 我会尽量避免使用复合键。如果不可能,请编写一个代表组合键的类。这使得处理它变得更加容易。
  • 我会尽量避免不基于主键的关系。可能有理由不这样做,NH支持他们,我只是认为他们制造麻烦。

会议为何关闭?我不知道,我会看一下堆栈跟踪。异常真的是从 using 块中抛出的吗?或者它是从TestCleanup方法中抛出的?