nhibernate fetching-strategy

NHibernate Eager Obteniendo MĂșltiples Niveles



fetching-strategy (5)

Tengo una jerarquía de entidades de tres niveles: Customer-Order-Line, que me gustaría recuperar en su totalidad para un cliente dado, usando ISession.Get (id). Tengo los siguientes fragmentos XML:

customer.hbm.xml:

<bag name="Orders" cascade="all-delete-orphan" inverse="false" fetch="join"> <key column="CustomerID" /> <one-to-many class="Order" /> </bag>

order.hbm.xml:

<bag name="Lines" cascade="all-delete-orphan" inverse="false" fetch="join"> <key column="OrderID" /> <one-to-many class="Line" /> </bag>

He utilizado el atributo fetch = "join" para indicar que quiero buscar las entidades secundarias para cada padre, y esto ha construido el SQL correcto:

SELECT customer0_.ID AS ID8_2_, customer0_.Name AS Name8_2_, orders1_.CustomerID AS CustomerID__4_, orders1_.ID AS ID4_, orders1_.ID AS ID9_0_, orders1_.PostalAddress AS PostalAd2_9_0_, orders1_.OrderDate AS OrderDate9_0_, lines2_.OrderID AS OrderID__5_, lines2_.ID AS ID5_, lines2_.ID AS ID10_1_, lines2_.[LineNo] AS column2_10_1_, lines2_.Quantity AS Quantity10_1_, lines2_.ProductID AS ProductID10_1_ FROM Customer customer0_ LEFT JOIN [Order] orders1_ ON customer0_.ID=orders1_.CustomerID LEFT JOIN Line lines2_ ON orders1_.ID=lines2_.OrderID WHERE customer0_.ID=1

Hasta ahora, esto se ve bien: SQL devuelve el conjunto correcto de registros (con solo un orderid distinto), pero cuando ejecuto una prueba para confirmar el número correcto de entidades (desde NH) para pedidos y líneas, obtengo los resultados incorrectos

Debería obtener (de mis datos de prueba), 1xOrder y 4xLine, sin embargo, obtengo 4xOrder y 4xLine. Parece que NH no reconoce el grupo de "repetición" de información de orden en el conjunto de resultados, ni "reutiliza" correctamente la entidad de orden.

Estoy usando todos los ID enteros (PK), y he intentado implementar IComparable de T y IEquatable de T usando esta ID, con la esperanza de que NH vea la igualdad de estas entidades. También he intentado descartar Equals y GetHashCode para usar la ID. Ninguno de estos ''intentos'' ha tenido éxito.

¿Es la operación de recuperación de niveles múltiples una operación compatible para NH, y si es así, hay una configuración XML requerida (o algún otro mecanismo) para soportarla?

NB: utilicé la solución de sirocco con algunos cambios en mi propio código para finalmente resolver este. el xml debe cambiarse de una bolsa a otra, para todas las colecciones, y las entidades se cambiaron para implementar IComparable <>, que es un requisito de establecer un conjunto único.

public class BaseEntity : IComparable<BaseEntity> { ... private Guid _internalID { get; set; } public virtual Guid ID { get; set; } public BaseEntity() { _internalID = Guid.NewGuid(); } #region IComparable<BaseEntity> Members public int CompareTo( BaseEntity other ) { if ( ID == Guid.Empty || other.ID == Guid.Empty ) return _internalID.CompareTo( other._internalID ); return ID.CompareTo( other.ID ); } #endregion ... }

Tenga en cuenta el uso de un campo InternalID. Esto es necesario para entidades nuevas (transitorias); de otro modo, no tendrán inicialmente una ID (mi modelo las ha suministrado cuando se guardaron).


Obtiene 4XOrder y 4XLines porque la unión con líneas duplica los resultados. Puede configurar un transformador en la ICriteria como:

.SetResultTransformer(new DistinctRootEntityResultTransformer())


@Tigraine: su consulta solo devuelve Publicaciones con comentarios. Esto trae todas las publicaciones con todos los comentarios (2 niveles). Lo que pide Ben es que el cliente ordene a LineItem (nivel 3). @Ben: que yo sepa, nHibernate aún no soporta la carga ansiosa de hasta 3 niveles. Hibernate lo apoya tú.


Acabo de leer el blogpost de Ayende donde utilizó el siguiente ejemplo:

session.CreateCriteria(typeof(Post)) .SetFetchMode("Comments", FetchMode.Eager) .List();

En una consulta de criterios para evitar la carga diferida en una consulta en particular

Quizás eso pueda ayudarte.


Estaba teniendo el mismo problema. Ver este hilo No obtuve una solución, pero una pista de Fabio. Usa Set en lugar de bolsa. Y funcionó.

Entonces mi sugerencia es intentar usar el conjunto. No tiene que usar la colección Iesi use IDictonary y NH está feliz

public override IEnumerable<Baseline> GetAll() { var baselines = Session.CreateQuery(@" from Baseline b left join fetch b.BaselineMilestones bm left join fetch bm.BaselineMilestonePrevious ") .SetResultTransformer(Transformers.DistinctRootEntity) .List<Baseline>(); return baselines; }


Si necesita mantener su uno-a-manys como bolsas, entonces puede emitir 2 consultas, cada una con solo 1 nivel de jerarquía. por ejemplo, algo como esto:

var temp = session.CreateCriteria( typeof( Order ) ) .SetFetchMode( "Lines", NHibernate.FetchMode.Eager ) .Add( Expression.Eq( "Customer.ID", id ) ) .List(); var customer = session.CreateCriteria( typeof( Customer ) ) .SetFetchMode( "Orders", NHibernate.FetchMode.Eager ) .Add( Expression.Eq( "ID", id ) ) .UniqueResult();

Las líneas se cargan en el caché NH en la primera consulta, por lo que no necesitarán una carga diferida cuando accedan más tarde, por ejemplo, al cliente. Pedidos [0]. Líneas [0].