【问题标题】:NHibernate: Join collection on other than composite keys specified in mappingNHibernate:在映射中指定的复合键以外的其他组合键上加入集合
【发布时间】:2012-02-01 13:20:17
【问题描述】:

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

映射如下所示:

<?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 删除重复项...


更新:我已尝试删除复合键映射,但随后我收到一个显然抛出的错误,因为即使我尝试忽略复合外键也会强制执行。那么说服 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”连接,如下所示,但这里也没有填充 children 集合:

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

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

【问题讨论】:

  • 你能发布你想要获取的实际 SQL 吗?

标签: nhibernate join hql composite-key


【解决方案1】:

我认为您对此采取了错误的方法。一对多关系映射是关系数据库中外键关系的面向对象等价物。在这种情况下,过滤或获取子集合的不同视图的能力没有意义。假设你能做到,NHibernate 怎么能持久化过滤后的子集合的变化呢?如果 NHibernate 不能持久化它,那么它的建模不正确。您还希望“通过优先选择“ChangedDate”和“ChangedTime”两列中具有最高值的条目来清除任何重复的子项”,这强化了这一结论。

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

另一个选项是向 FcoTransportation 添加一个过滤子集合的方法。如果寄售数量合理(

【讨论】:

  • 谢谢。好吧,如果我做错了什么,那么它将在这种特殊情况下使用 NHibernate。我只需要从表中取出数据,而不是再次将它们保存回来,因此弄乱父子关系对我来说并不是真正的问题。我只需要以最有效的方式将其取出并发送即可。我已经有一个查询来获取每个运输的货物(最多几十个,但通常是几个,在某些孤立的情况下几百个)。我只是想在往返数据库的数量上保持经济。
  • NHibernate 适合这种情况,您可以将数据库访问次数减少到 1,但可能不会减少查询次数。我不认为你可以通过加入来做到这一点。
  • 如何将数据库访问次数减少到 1?我可能没有应用最经济的 NHibernate 会话和事务用法...... Thnx。
【解决方案2】:

目前你只是加入而不是获取孩子,所以尝试使用“加入获取”而不是仅仅加入:

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

这应该可以解决问题。

【讨论】:

  • 这听起来很有希望,但我无法让它发挥作用。我已经更新了我的问题供您查看。
【解决方案3】:

试试这个

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

我不知道从 FcoConsignment 到 FcoTransportation 的导航属性的名称,所以我将其命名为运输。

【讨论】:

  • 不。我认为它确实应该涉及某种加入。
  • 我使用的连接类型称为“theta 样式连接”。在发布我的答案之前,我会在测试域上检查它们。
  • 有趣!那么这也应该填充子集合吗?但它也不起作用,miracleforhire 的其他建议也不起作用,所以可能有其他问题。
猜你喜欢
  • 1970-01-01
  • 2017-08-06
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 2017-02-21
  • 2019-04-22
相关资源
最近更新 更多