nhibernate在多对一实体上生成左外部联接

标签 nhibernate outer-join

我正在使用nHibernate 2.1.2,并认为nhibernate将在嵌套的多对一实体上生成左外部联接。似乎从实体Organization开始,在第3个嵌套注释上开始生成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>

最佳答案

如果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的内部工作原理。

关于nhibernate在多对一实体上生成左外部联接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3100757/

相关文章:

asp.net-mvc - S#arp 架构 vs 直接 IOC + NHibernate + MVC

mysql - 使用 NHibernate 执行 MySql 全文搜索

MYSQL 外连接,不返回不匹配的行

Python:单独取矩阵每一行的外积,取和然后返回一个和向量

linq - 使用 LINQ to NHibernate 将 LINQ IQueryable 转换为分页 IQueryable

nhibernate - 有外键但被引用的行不存在时,是否可以避免NHibernate.ObjectNotFoundException?

SQL : where vs. 加入中

sql - 在 SQLAlchemy 中加入 outerjoin 之后

sql-server - 需要帮助在 MS Access 中实现完全外部联接

c# - FluentNHibernate 无法从 web.config 中读取 connectionString