我正在使用nHibernate 2.1.2并重新认为nhibernate将在嵌套的多对一实体上生成左外连接。它似乎开始在第三个嵌套音符上生成left-outer-join,从实体组织开始。我在映射文件中设置了以下强制使用内连接,我在映射文件中错过了什么?真的希望有人能给我一个暗示。感谢任何帮助!
lazy="false" fetch="join"
示例参与和关系: 销售记录 - 员工 - 组织
nhibernate生成:
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>
Employee.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>
答案 0 :(得分: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个实体。 TableChild的一个实体和TableParent的一个实体。
在第一个查询中,您只能获得TableChild实体,在某些情况下,p.Name将被忽略(在第二级进行probalby),它会在检查引用TableParent的属性时重新查询数据库。
当我想加载只有一次命中数据库的树结构时,我发现了这一点:
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,结构不会只加载一个查询。我不得不使用LeftOuterJoin,以便NHibernate识别实体。
执行的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的内部工作原理。