2010-02-19 16 views
8

i tienen una clase padre que tiene dos colecciones hijas ChildCollectionA y ChildCollectionB. ChildCollectionA está asignada como una asociación, y tiene su propio ID:Nhibernate: carga ansiosa dos colecciones hijas (uno de ellos una lista de componentes)

HasMany(parent => parent.ChildCollectionA) 
.KeyColumn("IDParent") 
.AsBag().Cascade.AllDeleteOrphan(); 

y ChildCollectionB se asigna tiene una lista de componentes:

HasMany(parent => parent.ChildCollectionB) 
    .Table("ChildCollectionBTable") 
    .KeyColumn("IDParent") 
    .Component(m=> 
       { 
        m.References(childB => childB.Task, "IDTask").Not.LazyLoad().Not.Nullable(); 
        m.Map(childB => childB.Date, "Date").Not.Nullable(); 

       } 
     ) 
    .AsBag().Cascade.AllDeleteOrphan(); 

que necesito ahora todos los padres en la base de datos, porque voy a tiene que realizar algunas operaciones que necesitan tanto ChildCollectionA como ChildCollectionB.

así que tuve que carga ansiosa ellos, utilizado para ir a buscar el modo de carga ChildCollectionA ansiosos primera:

queryParents var = session.createCriteria() .SetFetchMode ("ChildCollectionA", FetchMode.Eager) .Add (Expression.Le ("ParentDate", endDate));

Volvió 492 padres (debe ser de 481), el valor total de la operación que hice fue 32,847.46 € (debe ser 30,790.87 €). Así que tiene que eliminar duplicados para los padres:

var queryParents = session.CreateCriteria<Parent>() 
    .SetFetchMode("ChildCollectionA", FetchMode.Eager) 
    .Add(Expression.Le("ParentDate",endDate)) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

Probé la misma carga ansiosos con sólo el ChildCollectionB

var queryParents = session.CreateCriteria<Parent>() 
    .SetFetchMode("ChildCollectionB", FetchMode.Eager) 
    .Add(Expression.Le("ParentDate",endDate)) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

En ambos casos los padres devuelto 481 OK, y el valor era de 30,790.87 € OK.

pero necesitaba la carga ansiosa ambas colecciones al mismo tiempo, me hicieron esto:

var queryParents = session.CreateCriteria<Parent>() 
    .SetFetchMode("ChildCollectionA", FetchMode.Eager) 
    .SetFetchMode("ChildCollectionB", FetchMode.Eager) 
    .Add(Expression.Le("ParentDate",endDate)) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

Volvió 481 padres OK, y el valor era de 32,602.57 € (debe ser 30,790.87 €).

Ahora el número de padres devueltos es correcto, pero hay duplicados en otro lugar, los valores dependen de las colecciones y no del elemento principal, por lo que los duplicados deben estar en algún lugar de ChildCollections.

Ahora estoy usando una solución fea:

var queryParents = session.CreateCriteria<Parent>() 
    .SetFetchMode("ChildCollectionA", FetchMode.Eager) 
    .Add(Expression.Le("ParentDate",endDate)) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

parents= queryParents.List<Parent>(); 

    foreach (Parent p in parents) 
    { 
     NHibernateUtil.Initialize(p.ChildCollectionB); 
    } 

volvió padres 481 OK, y el valor era de 30,790.87 € OK.

El problema ocurre cuando la carga ansiosa ambas colecciones, si la carga ansiosa sólo uno, y luego forzar el lazyload a la otra, sus obras. No sé si el mapeo de ChildCollectionB ser una lista de componentes en lugar de una asociación tiene algo que ver con esto ...

Alguna pista?

Gracias

Respuesta

4

creo que el problema es el producto cartesiano entre las dos colecciones no se maneja por el DistinctRootEntityTransformer ... por lo que ha duplicado los datos de las colecciones en alguna parte.

Para cargar varias colecciones con impaciencia que va a tomar varias consultas.

var queryParents = session.CreateCriteria<Parent>() 
    .SetFetchMode("ChildCollectionA", FetchMode.Eager) 
    .Add(Expression.Le("ParentDate",endDate)) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

//load CollectionB in second query...it's linked together by NH 
session.CreateCriteria<Parent>() 
    .SetFetchMode("ChildCollectionB", FetchMode.Eager) 
    .Add(Expression.Le("ParentDate",endDate)) 
    .List(); 

Lo que normalmente hago es buscar la entidad principal junto con todas las asociaciones necesarias de muchos a uno. Luego buscaré ansiosamente las colecciones requeridas en la sesión con un MultiCriteria. Si solo son dos colecciones, a veces me gusta más arriba y busco la primera colección con distinción.

Para más información ver Eager loading aggregate with many child collections

+0

Cualquier idea de si esto se ha probado con la versión 4.0.4 nhibernate 4 en concreto? Parece que esta solución no funciona en esa versión. –

Cuestiones relacionadas