NHibernate:在映射中指定的复合键之外加入集合

时间:2012-02-01 13:20:18

标签: nhibernate join hql composite-key

在旧数据库中,我必须使用通过组合键关联的嵌套表。翻译成NHibernate,我有例如一个类FcoTransportation,它有一个FcoConsignment类的子集合。但是,在一种情况下,我想仅基于组合键的一个组件加载集合,而忽略另一个组件。

映射如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
  <class name="FcoLib.FcoTransportation, FcoLib" table="FCO_TRANSPORTATION">
    <composite-id>
    <key-property name="ID"/>
  <key-property name="FK_EventID"/>
</composite-id>
<!--...snip...-->
<bag name="Consignments" table="FCO_Consignment" lazy="false" cascade="save-update">
  <key>
    <column name="FK_TransportationID"/>
    <column name="FK_EventID"/>
  </key> 
  <one-to-many class="FcoLib.FcoConsignment, FcoLib"/>
</bag>
<!--...snip...-->

我一直在尝试使用普通的NHibernate标准,SQL和HQL创建此查询。 这是我迄今为止在HQL中所获得的,至少可以无错误地加载传输:

 String queryString = "select ft from FcoTransportation as ft";
 queryString += " join ft.Consignments as fc on fc.FK_TransportationID = :ID";

 var query = session.CreateQuery(queryString);

 transports = query
                .SetMaxResults(100)
                .List<FcoTransportation>();  

然而,货物的收集仍然是空的!我该如何解决这个问题??

作为一个额外的,我想通过分别在两列“ChangedDate”和“ChangedTime”中选择具有最高值的条目来淘汰任何重复的孩子。


作为最后的手段,我正在考虑完全删除复合键映射。在这种情况下,我仍然需要根据最新的ChangedDate / ChangedTime删除重复...


UPDATE :我尝试删除复合键映射,但后来我收到一个显然被抛出的错误,因为即使我尝试忽略复合外键也会强制执行。那么说服NHibernate不强制执行此操作的诀窍是什么,因为我可以在SQL Srv Mgt Studio中轻松编写SQL查询来执行此操作:

SELECT TOP 100 *
  FROM [FCO_EVENT] AS e 
  INNER JOIN [FCO_TRANSPORTATION] AS t ON e.FK_TransportationID = t.ID
  --children:
  LEFT OUTER  JOIN [FCO_CONSIGNMENT] AS c ON c.FK_TransportationID = t.ID 
  LEFT OUTER JOIN [FCO_CONSIGNMENT_LINES] AS cl ON cl.FK_ConsignmentID = c.ID 

更新:建议使用联接提取,看起来很有前景,但仍然没有提取子项:

 String queryString = "select ft from FcoTransportation as ft where ft.ID ='" + guid + "'";
 queryString += " join fetch ft.Consignments as fc on fc.FK_TransportationID = '" + guid + "'";

更新:还建议进行所谓的“theta-style”加入,如下图所示,但在这里,未收集子集合:

String queryString  = "select ft from FcoTransportation as ft, FcoConsignment as fc"
                    + " where ft.ID = fc.FK_TransportationID"
                    + " and ft.ID = '" + guid + "'";

注意:我只需要取出数据,而不是再将其保存。我已经有一个查询来获取每个运输的货物(最多是几十个,但通常是几个,在一些孤立的情况下几百个)。我只想通过数据库的往返量来获得经济效益。这就是为什么我希望在同时运输货物的同时取出货物。

3 个答案:

答案 0 :(得分:1)

我认为你对此采取了错误的做法。一对多关系映射是面向对象的等价于关系数据库中的外键关系。在此上下文中,过滤或获取子集合的不同视图的能力没有意义。假设你可以这样做,NHibernate如何将更改保留到已过滤的子集合?如果NHibernate无法持久化,那么它的模型不正确。您希望通过优先选择两列中具有最高值的条目“ChangedDate”和“ChangedTime”来“清除任何重复的孩子”,这加强了这一结论。

我只想创建一个查询来返回您想要的货物。使用Future,您可以将它包装在一个方法中,该方法将返回FcoTransportation对象,并且查询将导致数据库的单次访问。

另一种选择是向FcoTransportation添加一个过滤子集合的方法。如果托运数量合理(<10000?)并且您经常需要以这种方式过滤集合,那么我会选择此选项。

答案 1 :(得分:0)

目前您只是加入而不是抓取孩子,所以尝试使用“join fetch”而不是仅仅加入:

select ft from FcoTransportation as ft join fetch ft.Consignments as fc on fc.FK_TransportationID = :ID

这应该可以解决问题。

答案 2 :(得分:0)

试试这个

select ft from FcoTransportation as ft, FcoConsignment as fc
where ft.Id = fc.Transportation.Id

我不知道从FcoConsignment到FcoTransportation的导航属性的名称,因此我将其命名为Transportation。