6

我们有一个无法更改的遗留数据库。我们正试图转移到 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>

堵塞

<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.GroupPartner兴趣:

我有一个单元测试:

[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
公司 'LALA':
公司 'LALA SA':
Block #2 公司
'BG PO':
公司 'LIMPOPO': 公司 'HAHA': 公司'Other partner(s)' 公司: Block #4




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

NHibernate.LazyInitializationException: Initializing[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 navigator 的元素中删除“property-ref=GroupId”,我将得到以下异常:

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

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

谢谢,亚历克斯

4

1 回答 1

2

The problem is the following:

  • If you have a entity with a composite id, all references to it must maintain the composite id, so there must be two foreign keys.
  • Blocks in GroupPartnerInterest is a set, so the foreign key is in Blocks, pointing to GroupPartnerInterest. It would require two foreign keys, which are not available.
  • property-ref is to replace the primary key with some other property. It is therefore a property of the table on the one-side of the relation, which is GroupPartnerInterest, but there is no GroupId.
  • You could probably use property-ref for GroupPartnerInterest.Blocks (because the two foreign keys are missing, to make Block.PAR_ID point to GPI.PAR_ID), but I would think twice about it.

I can't give you a working solution here. I don't use composite keys and this is more complex. But there are some more thoughts:

  • I would try to avoid the composite key. If it is not possible, write a class which represents the composite key. This makes it much easier to handle it.
  • I would try to avoid relations that are not based on the primary key. There may be reasons to do otherwise, NH supports them, I just think that they cause troubles.

Why is the session closed? I don't know, I would take a look at the stack trace. It the exception really thrown from within the using block? Or is it thrown from a TestCleanup method?

于 2010-08-26T06:52:59.150 回答