NHibernate在join-subclass继承属性上的一对多

时间:2013-10-08 17:16:50

标签: c# sql vb.net nhibernate orm

我正在使用带有.Net 4.0的NHibernate 3.3.3,并且面临NHibernate生成错误SQL的问题。

我有以下(简化)课程:

class Process 
{
    public Customer { get; set; }
    [additional properties]
}

class OrderProcess : Process 
{
    [further additional properties]
}

class FinishedProcess : Process 
{
    public DateTime SaveOn { get; set; }
}

class FinishedOrderProcess : FinishedProcess 
{
    [even more properties]
}

class Customer 
{
    public IList<OrderProcess> OrdersInProgess { get; set; }
    public IList<FinisheOrderProcess> FinishedOrders { get; set;}
    [additional properties]
}

使用这些类我已经使用hbm.xml文件为NHibernate映射它们,方法如下:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="tadoraOrm"
                   namespace="tadoraOrm.Models">

  <class name="Customer" table="CUSTOMER">
      <id column="REC_ID" name="Id">
          <generator class="identity" />
      </id>
      <bag name="FinishedOrders" inverse="true" cascade="none" lazy="true">
          <key column="CUSTOMER_ID"/>
          <one-to-many class="FinishedOrderProcess"/>
      </bag>
      <bag name="OrdersInProgess" inverse="true" cascade="none" lazy="true">
          <key column="CUSTOMER_ID"/>
          <one-to-many class="OrderProcess"/>
      </bag>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="tadoraOrm"
                   namespace="tadoraOrm.Models">
    <class name="Process" table="PROCESS" abstract="true">
        <id name="Id" column="REC_ID">
            <generator class="identity"/>
        </id>
        <joined-subclass name="FinishedProcess" table="FINISHED_PROCESS" abstract="true">
            <key column="PROCESS_ID"/>
            <joined-subclass name="FinishedOrderProcess" table="FINISHED_ORDER_PROCESS">
                <key column="FINISHED_PROCESS_ID"/>
            </joined-subclass>
        </joined-subclass>
        <joined-subclass name="OrderProcess" table="ORDER_PROCESS">
            <key column="ORDER_PROCESS_ID"/>
        </joined-subclass>
    </class>
</hibernate-mapping>

最后但并非最不重要的是这里是获取所有内容的代码(在VB.Net中)

Dim customers As IList(Of Customer) = session.CreateCriteria(Of Customer)().
    CreateAlias("FinishedOrders", "FO").
        Add(
            Restrictions.Between("FO.SavedOn", dtpFrom.Value.Date, dtpUntil.Value)
        ).List<Customer>()

这件事生成了这个SQL:

select
    *
from CUSTOMER C 
  inner join FINISHED_ORDER_PROCESS FOP 
    on C.REC_ID = FOP.CUSTOMER_ID
  left outer join FINISHED_PROCESS FP
    on FP.PROCESS_ID = FOP.FINISHED_PROCESS_ID
  left outer join PROCESS P
    on P.REC_ID = FP.PROCESS_ID
where FP.SavedOn between '2013-10-01T00:00:00' /* @p0 */ and '2013-10-08T17:53:50' /* @p1 */

这里的问题是FOP不包含它包含在PROCESS表中的CUSTOMER_ID列。更进一步,我希望所有连接都是内部连接,而不是最后两个表的左外连接。

基本上这个:

select
    *
from CUSTOMER C 
  inner join FINISHED_ORDER_PROCESS FOP 
    on C.REC_ID = P.CUSTOMER_ID
  inner join FINISHED_PROCESS FP
    on FP.PROCESS_ID = FOP.FINISHED_PROCESS_ID
  inner join PROCESS P
    on P.REC_ID = FP.PROCESS_ID
where FP.SavedOn between '2013-10-01T00:00:00' /* @p0 */ and '2013-10-08T17:53:50' /* @p1 */

我很抱歉发布了那么多代码,但我认为它解释了我面临的最佳问题。

使用这种继承策略的原因是除了以类似方式工作的订单之外,我还有几个不同的流程。

如果您已经知道如何使用NHibernate Criteria API,HQL或使用NHibernate的任何其他可能性来检索在指定时间范围内获得FOP的客户列表,我将非常感激,如果您可以分享。

如果缺少任何信息或问题似乎难以理解,请随时提出!

1 个答案:

答案 0 :(得分:3)

在这种情况下我们要做的是正确导航NHibernate,其中对象关系表关系。这种情况下的关系在表Process上的基类Process上定义。

所以,映射应该是这样的:

<bag name="FinishedOrders" inverse="true" cascade="none" lazy="true">
    <key column="CUSTOMER_ID"/>

    <!-- instead of that -->
    <!-- <one-to-many class="FinishedOrderProcess"/>-->

    <!-- use this -->
    <one-to-many class="Process"/>
</bag>

编辑:在这种情况下,Process集合(客户实体)的映射必须更改为IList<Process>。这实际上与当前的数据库设计有关,其中客户与流程的关系是在流程抽象层面上定义的

下面讨论的广告,短期解决方案,可能是保留.net映射,如果我们将引入WHERE属性。如果我们在映射期间有足够的信息(例如在 Process 表中),我们可以区分哪些行将被加载为FinishedOrders,因此避免了转换异常。