2011-05-31 18 views
5

Tengo un objeto principal con una colección secundaria que contiene un elemento, la colección secundaria contiene una colección "nieto" que contiene 3 elementos.NHibernate ThenFetchMany está recuperando hijos duplicados

Estoy cargando el objeto principal de la base de datos utilizando NHibernate de la siguiente manera

Parent parentObject = session.Query<Parent>() 
    .FetchMany(x => x.Children) 
    .ThenFetchMany(x => x.GrandChildren) 
    .Where(x => x.Id = "someparentid") 
    .Single(); 

Lo que estoy encontrando es que hay niños duplicar objetos (3 en total) unido al objeto padre cuando no debería haber solo uno. (Hay 3 objetos de nieto correctamente conectados a cada niño.) La carga de la colección de niños solo funciona correctamente.

¿Sabes cómo puedo lograr cargar el objeto principal completo sin duplicar hijos?

Respuesta

2

pude usar la respuesta here usando QueryOver, se carga correctamente los objetos mientras generando SQL eficiente (selecciona por tabla en lugar de una combinación grande).

1

No puede hacerlo con NHibernate (tampoco creo que pueda hacerlo con EF4) ya que su resultado es un producto cartesiano. Obtienes todos los resultados de todas las tablas.

NHibernate no sabe cómo asignar los resultados de ambas colecciones a la raíz. Por lo tanto, para cada niño, obtienes el mismo número de GrandChildren, y para cada GrandChildren terminas con la misma cantidad de niños.

+0

@ J0K - Gracias por editar, no han tenido café de la mañana todavía me :) – Phill

+0

He perfilado la consulta SQL que se está generando y hay dos combinaciones a la izquierda, con una condición de combinación en la clave principal y una clave externa en ambas, por lo que estoy bastante seguro de que no es un producto cartesiano. Lo he logrado usando LinqToSql en el pasado. – Simon

+0

@Simon: tome la consulta y colóquela en SQL Server Management Studio y ejecute la consulta; verá todos los resultados de todas las tablas. Es posible obtener el mismo resultado, pero tendría que escribir HQL. Vea el blog de Ayende para gráficos de objetos profundos - http://ayende.com/blog/2580/efficently-loading-deep-object-graphs – Phill

5

Si asigna Niños y GrandChildren como conjunto, puede evitar el producto cartesiano. Es necesario definir hijos y nietos como colecciones:

public class Parent 
{ 
    ... 
    public virtual ICollection<Child> Children { get; set; } 
    ... 
} 

public class Child 
{ 
    ... 
    public virtual ICollection<GrandChild> GrandChildren { get; set; } 
    ... 
} 

Y en el mapeo (usando FluentNHibernate):

public class ParentMapping : ClassMap<Parent> 
{ 
    public ParentMapping() 
    { 
     ... 
     HasMany(x => x.Children) 
      .KeyColumn("ParentID") 
      .Inverse 
      .AsSet() 
     ... 
    } 
} 

public class ChildMapping : ClassMap<Child> 
{ 
    public ChildMapping() 
    { 
     ... 
     HasMany(x => x.GrandChildren) 
      .KeyColumn("ChildID") 
      .Inverse 
      .AsSet() 
     ... 
    } 
} 
+0

Para ser precisos, la consulta sigue ofreciendo el producto cartesiano, pero obtendrá un solo Perent. –

+0

¿Hay algún inconveniente en este enfoque que no experimentaría al utilizar QueryOver? –

+0

Gracias por esto. Descubrí que, en un caso similar, la directiva AsSet era suficiente para garantizar que no hubiera más duplicados. – mabian69

1

Si está utilizando LINQ, puede simplificar con esto:

int parentId = 1; 
var p1 = session.Query<Parent>().Where(x => x.ParentId == parentId); 

p1 
.FetchMany(x => x.Children) 
.ToFuture(); 

sess.Query<Child>() 
.Where(x => x.Parent.ParentId == parentId); 
.FetchMany(x => x.GrandChildren) 
.ToFuture(); 

Parent p = p1.ToFuture().Single(); 

explicación detallada aquí: http://www.ienablemuch.com/2012/08/solving-nhibernate-thenfetchmany.html

+0

Gracias Michael, aunque no he probado el código para probarlo, todos esos ejemplos vinculados fallan cuando los niños que se van a buscar (que también tienen nietos para buscar) están en una relación de muchos a muchos con el padre. He intentado con todo ese ejemplo (y muchos otros) y todos siguen produciendo productos cartesianos en este caso – PandaWood

+0

¡Esto funciona genial! –