3

我将 NHibernate 3.3.3 与 .Net 4.0 一起使用,并且面临 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 不包含列 CUSTOMER_ID 它包含在 PROCESS 表中。此外,我希望所有连接都是内连接,而不是最后两个表的左外连接。

基本上是这样的:

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 的客户列表,如果您能分享,我将不胜感激。

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

4

1 回答 1

3

What we have to do in this case, is correctly navigate NHibernate, where is the object relation i.e. table relationship. The relation in this case is defined on the base class Process, on the table Process.

So, the mapping should be like this:

<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>

Edit: In this case, the mapping of the Process collections (Customer entity) must be changed to be IList<Process>. This in fact relates to the current DB design, where relation Customer to Process is defined on that Process abstract level

Ad discussed below, the short term solution, could be to leave the .net mapping as it is, if we will introduce the WHERE attribute. If we have enough information during the mapping (e.g. in the Process table) we can distinguish which rows will be loaded as FinishedOrders, therefore avoid the casting exception.

于 2013-10-09T04:36:23.063 回答