2010-06-23 59 views
5

我使用的是nHibernate 2.1.2,并认为nhibernate会在嵌套的多对一实体上生成左外连接。似乎开始生成从实体Organization开始的第3个嵌套注释向左外连接。我在映射文件中设置了以下内容以强制使用inner-join,在映射文件中有什么遗漏了?真的希望有人能给我一个提示。感谢任何帮助!nhibernate在多对一的实体上生成左外连接

lazy="false" fetch="join" 

例的entites和关系: 销售记录 - 员工 - 组织

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> 
+1

查询的外观如何?你使用HQL还是标准? – 2010-06-23 12:08:38

+0

我只是做Entity.Fetch,顺便说一句,我也测试过HQL和同样的问题。 – ksang 2010-07-01 08:28:53

+0

我已经通过修改nhibernate源码修复了这个问题,我发现nhibernate只会为第一级连接生成innerjoint sql。也许有人可以告诉我为什么它的行为如此。 – ksang 2010-07-02 05:59:24

回答

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的内部工作。