NHibernate渴望获得多个级别

Ben*_*aan 19 nhibernate fetching-strategy

我有一个3级实体层次结构:Customer-Order-Line,我想使用ISession.Get(id)为给定客户完整检索.我有以下XML片段:

customer.hbm.xml:

<bag name="Orders" cascade="all-delete-orphan" inverse="false" fetch="join">
  <key column="CustomerID" />
  <one-to-many class="Order" />
</bag>
Run Code Online (Sandbox Code Playgroud)

order.hbm.xml:

<bag name="Lines" cascade="all-delete-orphan" inverse="false" fetch="join">
  <key column="OrderID" />
  <one-to-many class="Line" />
</bag>
Run Code Online (Sandbox Code Playgroud)

我使用了fetch ="join"属性来表示我想为每个父项获取子实体,这构造了正确的SQL:

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
Run Code Online (Sandbox Code Playgroud)

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

应该(从我的测试数据),1xOrder和4xLine,但是,我得到4xOrder和4xLine.NH似乎没有认识到结果集中的"重复"订单信息组,也没有正确地"重复使用"订单实体.

我正在使用所有整数ID(PK),并且我尝试使用此ID实现T的IComparable和T的IEquatable,希望NH能够看到这些实体的相等性.我也尝试重写Equals和GetHashCode来使用ID.这些"尝试"都没有成功.

"多级提取"是NH支持的操作,如果是,是否需要XML设置(或其他一些机制)来支持它?


注意:我使用了sirocco的解决方案,对我自己的代码进行了一些更改,最终解决了这个问题.对于所有集合,需要将xml从bag更改为set,并且更改权限本身以实现IComparable <>,这是要设置唯一性的集合的要求.

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

    ...

 }
Run Code Online (Sandbox Code Playgroud)

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

sir*_*cco 21

你得到4XOrder和4XLines,因为与行的连接使结果加倍.您可以在ICriteria上设置Transformer,如:

.SetResultTransformer(new DistinctRootEntityResultTransformer())
Run Code Online (Sandbox Code Playgroud)

  • 我发现这确实解决了问题,*如果*映射从包更改为set,并且我在基类上实现了必要的IComparable <T>. (3认同)
  • 使用`.SetResultTransformer(new DistinctRootEntityResultTransformer())`进行两级预测加载很好,比开始生成笛卡尔连接更多 (3认同)

Tig*_*ine 5

我刚刚阅读了Ayende的Blogpost,他使用了以下示例:

session.CreateCriteria(typeof(Post))
    .SetFetchMode("Comments", FetchMode.Eager)
    .List();
Run Code Online (Sandbox Code Playgroud)

在Criteria Query中,以避免在一个特定查询上进行延迟加载

也许这可以帮到你.