我正在使用带有.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的客户列表,我将非常感激,如果您可以分享。
如果缺少任何信息或问题似乎难以理解,请随时提出!
答案 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
,因此避免了转换异常。