首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >多个级别的NHibernate急切获取

多个级别的NHibernate急切获取
EN

Stack Overflow用户
提问于 2008-12-02 00:44:09
回答 5查看 16.6K关注 0票数 19

我有一个三级的实体层次结构: Customer-Order-Line,我希望使用ISession.Get(id)为给定的客户检索它。我有以下XML片段:

customer.hbm.xml:

代码语言:javascript
运行
复制
<bag name="Orders" cascade="all-delete-orphan" inverse="false" fetch="join">
  <key column="CustomerID" />
  <one-to-many class="Order" />
</bag>

order.hbm.xml:

代码语言:javascript
运行
复制
<bag name="Lines" cascade="all-delete-orphan" inverse="false" fetch="join">
  <key column="OrderID" />
  <one-to-many class="Line" />
</bag>

我使用了fetch="join“属性来指示我想要获取每个父实体的子实体,这已经构造了正确的SQL:

代码语言:javascript
运行
复制
SELECT 
    customer0_.ID AS ID8_2_, 
    customer0_.Name AS Name8_2_, 
    orders1_.CustomerID AS CustomerID__4_, 
    orders1_.ID AS ID4_, 
    orders1_.ID AS ID9_0_, 
    orders1_.PostalAddress AS PostalAd2_9_0_, 
    orders1_.OrderDate AS OrderDate9_0_, 
    lines2_.OrderID AS OrderID__5_, 
    lines2_.ID AS ID5_, 
    lines2_.ID AS ID10_1_, 
    lines2_.[LineNo] AS column2_10_1_, 
    lines2_.Quantity AS Quantity10_1_, 
    lines2_.ProductID AS ProductID10_1_ 

FROM Customer customer0_ 

LEFT JOIN [Order] orders1_ 
       ON customer0_.ID=orders1_.CustomerID 

LEFT JOIN Line lines2_ 
       ON orders1_.ID=lines2_.OrderID 

WHERE customer0_.ID=1

到目前为止,这看起来还不错- SQL返回了正确的一组记录(只有一个不同的orderid),但是当我运行一个测试来确认Orders和Lines的正确实体数量(来自NH)时,我得到了错误的结果

我应该得到(从我的测试数据),1xOrder和4xLine,然而,我得到了4xOrder和4xLine。似乎NH没有识别结果集中的“重复”订单信息组,也没有正确地“重用”订单实体。

我使用的是全整数ID (PKs),并且我已经尝试使用这个ID实现T的IComparable和T的IEquatable,希望NH会看到这些实体是相等的。我也尝试过重写Equals和GetHashCode来使用ID,但这两个“尝试”都没有成功。

NH是否支持“多级获取”操作?如果是,是否需要XML设置(或其他机制)来支持它?

注:我使用了sirocco的解决方案,并对我自己的代码做了一些修改,最终解决了这个问题。对于所有的集合,需要从一个包到另一个集合更改xml,并且实体本身也被更改以实现IComparable<>,这是要建立唯一性的集合的要求。

代码语言:javascript
运行
复制
public class BaseEntity : IComparable<BaseEntity>
{
    ...

    private Guid _internalID { get; set; }
    public virtual Guid ID { get; set; }

    public BaseEntity()
    {
        _internalID = Guid.NewGuid();
    }

    #region IComparable<BaseEntity> Members

    public int CompareTo( BaseEntity other )
    {
        if ( ID == Guid.Empty || other.ID == Guid.Empty )
            return _internalID.CompareTo( other._internalID );

        return ID.CompareTo( other.ID );
    }

    #endregion

    ...

 }

请注意InternalID字段的用法。这对于新的(瞬态)实体是必需的,否则它们最初不会有ID (我的模型在保存时会提供ID)。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2008-12-15 12:45:19

您将获得4XOrder和4XLines,因为join with lines会使结果加倍。您可以在ICriteria上设置变压器,如下所示:

代码语言:javascript
运行
复制
.SetResultTransformer(new DistinctRootEntityResultTransformer())
票数 21
EN

Stack Overflow用户

发布于 2008-12-02 08:48:35

我刚刚阅读了Ayende's Blogpost,他在其中使用了以下示例:

代码语言:javascript
运行
复制
session.CreateCriteria(typeof(Post))
    .SetFetchMode("Comments", FetchMode.Eager)
    .List();

在条件查询中,以避免对特定查询的延迟加载

也许这能帮到你。

票数 5
EN

Stack Overflow用户

发布于 2011-11-25 07:54:21

如果您需要将一对多作为包,那么您可以发出两个查询,每个查询只有一个层次结构。例如,类似于:

代码语言:javascript
运行
复制
var temp = session.CreateCriteria( typeof( Order ) )
    .SetFetchMode( "Lines", NHibernate.FetchMode.Eager )
    .Add( Expression.Eq( "Customer.ID", id ) )
    .List();

var customer = session.CreateCriteria( typeof( Customer ) )
    .SetFetchMode( "Orders", NHibernate.FetchMode.Eager )
    .Add( Expression.Eq( "ID", id ) )
    .UniqueResult();

在第一个查询中,行被加载到NH缓存中,因此在以后访问例如customer.Orders.Lines时,它们将不需要延迟加载。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/332703

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档