2010-06-23 12 views
5

estoy usando nHibernate 2.1.2 y he aprovechado que nhibernate generará combinación externa izquierda en entidades anidadas de muchos a uno. parece que start start genera left-outer-join en la tercera nota anidada en adelante que comienza desde la entidad Organization. He establecido el siguiente en el archivo de mapeo para forzar el uso de la unión interna, ¿tengo algo que haya perdido en el archivo de mapeo? realmente espero que alguien pueda darme una pista sobre esto. apreciar cualquier ayuda!nhibernate generar combinación externa izquierda en entidad uno a uno

lazy="false" fetch="join" 

Ejemplo ENTIDADES y Relaciones: récord de ventas - Empleados - Organización

nhibernate generan:

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

¿Cómo es la consulta? ¿Estás usando HQL o criterios? –

+0

Acabo de hacer Entity.Fetch, por cierto probé con HQL y el mismo problema. – ksang

+0

he solucionado este problema mediante una fuente de nhibernate modificada, descubrí que nhibernate solo generará sqjo de unión interna para el primer nivel de unión. tal vez alguien podría decirme por qué se comporta de esa manera. – ksang

Respuesta

4

Si NHibernate hace una combinación interna no lo hace Identificación de un niño y el ID de una tabla primaria (pero son lo mismo).

Ejemplo:

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

Si NHibernate hace una combinación interna, que se obtiene:

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

Si NHibernate hace una combinación externa izquierda, se obtiene:

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

Y porque del funcionamiento interno de NHibernate puede crear 2 entidades a partir de la segunda consulta. Una entidad para TableChild y otra para TableParent.

En la primera consulta solo obtendría la entidad TableChild y, en algunos casos, el p.Name se ignoraría (probalby en el segundo nivel) y requeriría que la base de datos revise la propiedad que hace referencia a TableParent.

me descubrió esto cuando quería cargar una estructura de árbol con un solo golpe a la base de datos:

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(); 
     } 
    } 
} 

Y la consulta que utilicé fue la siguiente:

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(); 

Con NHibernate.SqlCommand .JoinType.LeftOuterJoin. Porque si utilicé InnerJoin, la estructura no se cargó con una sola consulta. Tuve que usar LeftOuterJoin, para que NHibernate reconociera las entidades.

consultas SQL que ejecutó fueron:

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 

donde la primera consulta se deja combinación externa y tenemos 2 campos adicionales: t1_.id_SysPermissionTree_Parent como id4_4_, t1_.ID como ID4_

Así que lo que Estoy tratando de decirte que si usas NHibernate, la combinación externa izquierda es a veces una obligación para cumplir con el funcionamiento interno de NHibernate.

Cuestiones relacionadas