5

私は nHibernate 2.1.2 を使用しており、nhibernate がネストされた多対 1 エンティティで左外部結合を生成することを確認しました。エンティティ Organization から始まる 3 番目のネストされたノート以降で left-outer-join を生成し始めるようです。内部結合を強制的に使用するようにマッピング ファイルで次のように設定しました。マッピング ファイルで見逃したものはありますか? 誰かが私にこれについてのヒントを教えてくれることを本当に願っています. どんな助けにも感謝します!

lazy="false" fetch="join"

実体と関係の例: 販売記録 - 従業員 - 組織

休止状態生成:

select...
from sales 
inner join employee
left outer join organization

Sales.hbm.xml

<many-to-one name="Employee" insert="true" update="true" access="field.pascalcase-underscore" not-null="true" lazy="false" fetch="join"/>
<column name="EmployeeId" not-null="true"/>
</many-to-one>

従業員.hbm.xml

<many-to-one name="Organization" insert="true" update="true" access="field.pascalcase-underscore" not-null="true" lazy="false" fetch="join"/>
<column name="OrgId" not-null="true"/>
</many-to-one>
4

1 に答える 1

4

NHibernate が内部結合を行う場合、子テーブルから ID を取得せず、親テーブルから ID を取得しません (ただし、それらは同じです)。

例:

  TableParent (ID, Name)
  TableChild (ID, ID_TableParent, ....)

nHibernate が内部結合を行う場合、次のようになります。

 select c.ID, c.ID_TableParent, p.Name
 from TableChild c
 inner join TableParent p on p.ID = c.ID_TableParent

nHibernate が左外部結合を行う場合、次のようになります。

 select c.ID, c.ID_TableParent, p.ID, p.Name
 from TableChild c
 left outer join TableParent p on p.ID = c.ID_TableParent

また、NHibernate の内部動作により、2 番目のクエリから 2 つのエンティティを作成できます。TableChild 用の 1 つのエンティティと TableParent 用の 1 つのエンティティ。

最初のクエリでは、TableChild エンティティのみを取得し、場合によっては p.Name が無視され (おそらく第 2 レベルで)、TableParent を参照するプロパティをチェックする際にデータベースを再クエリします。

データベースへのヒットが 1 つだけのツリー構造をロードしたいときに、これを見つけました。

public class SysPermissionTree
{
    public virtual int ID { get; set; } 
    public virtual SysPermissionTree Parent { get; set; }
    public virtual string Name_L1 { get; set; }
    public virtual string Name_L2 { get; set; }

    public virtual Iesi.Collections.Generic.ISet<SysPermissionTree> Children { get; private set; }
    public virtual Iesi.Collections.Generic.ISet<SysPermission> Permissions { get; private set; }

    public class SysPermissionTree_Map : ClassMap<SysPermissionTree>
    {
        public SysPermissionTree_Map()
        {
            Id(x => x.ID).GeneratedBy.Identity();

            References(x => x.Parent, "id_SysPermissionTree_Parent");
            Map(x => x.Name_L1);
            Map(x => x.Name_L2);
            HasMany(x => x.Children).KeyColumn("id_SysPermissionTree_Parent").AsSet();
            HasMany(x => x.Permissions).KeyColumn("id_SysPermissionTree").AsSet();
        }
    }
}

そして、私が使用したクエリは次のとおりです。

SysPermissionTree t = null;
SysPermission p = null;

return db.QueryOver<SysPermissionTree>()
         .JoinAlias(x => x.Children, () => t, NHibernate.SqlCommand.JoinType.LeftOuterJoin)
         .JoinAlias(() => t.Permissions, () => p, NHibernate.SqlCommand.JoinType.LeftOuterJoin) 
         .Where(x => x.Parent == null)
         .TransformUsing(Transformers.DistinctRootEntity)
         .List();

NHibernate.SqlCommand.JoinType.LeftOuterJoin を使用。InnerJoin を使用した場合、構造は 1 つのクエリだけでは読み込まれませんでした。NHibernate がエンティティを認識できるように、LeftOuterJoin を使用する必要がありました。

実行された SQL クエリは次のとおりです。

SELECT this_.ID as ID28_2_, this_.Name_L1 as Name2_28_2_, this_.Name_L2 as Name3_28_2_, this_.id_SysPermissionTree_Parent as id4_28_2_, t1_.id_SysPermissionTree_Parent as id4_4_, t1_.ID as ID4_, t1_.ID as ID28_0_, t1_.Name_L1 as Name2_28_0_, t1_.Name_L2 as Name3_28_0_, t1_.id_SysPermissionTree_Parent as id4_28_0_, p2_.id_SysPermissionTree as id4_5_, p2_.ID as ID5_, p2_.ID as ID27_1_, p2_.Name_L1 as Name2_27_1_, p2_.Name_L2 as Name3_27_1_, p2_.id_SysPermissionTree as id4_27_1_ FROM [SysPermissionTree] this_ left outer join [SysPermissionTree] t1_ on this_.ID=t1_.id_SysPermissionTree_Parent left outer join [SysPermission] p2_ on t1_.ID=p2_.id_SysPermissionTree WHERE this_.id_SysPermissionTree_Parent is null
SELECT this_.ID as ID28_2_, this_.Name_L1 as Name2_28_2_, this_.Name_L2 as Name3_28_2_, this_.id_SysPermissionTree_Parent as id4_28_2_, t1_.ID as ID28_0_, t1_.Name_L1 as Name2_28_0_, t1_.Name_L2 as Name3_28_0_, t1_.id_SysPermissionTree_Parent as id4_28_0_, p2_.ID as ID27_1_, p2_.Name_L1 as Name2_27_1_, p2_.Name_L2 as Name3_27_1_, p2_.id_SysPermissionTree as id4_27_1_ FROM [SysPermissionTree] this_ inner join [SysPermissionTree] t1_ on this_.ID=t1_.id_SysPermissionTree_Parent inner join [SysPermission] p2_ on t1_.ID=p2_.id_SysPermissionTree WHERE this_.id_SysPermissionTree_Parent is null

ここで、最初のクエリは左外部結合であり、2 つの追加フィールドを取得します: t1_.id_SysPermissionTree_Parent は id4_4_ として、t1_.ID は ID4_ として

つまり、NHibernate を使用する場合、NHibernate の内部動作に準拠するために左外部結合が必要になる場合があるということです。

于 2011-10-05T10:53:58.173 に答える