nhibernate fluent-nhibernate eager-loading automapping

Carga impaciente usando NHibernate/Nhibernate y Automapping fluidos



fluent-nhibernate eager-loading (4)

Cada mapeo debe tener carga perezosa

en el mapa del nodo:

Map(x => x.EntityType).Not.LazyLoad();

en el mapa EnityType:

Map(x => x.Properties).Not.LazyLoad();

y así...

También, vea NHibernate Eager cargando objetos secundarios de múltiples niveles por una vez ansiosos por cargar

Adicional:

Información adicional sobre Sql N + 1:

http://nhprof.com/Learn/Alerts/SelectNPlusOne

Tengo un requisito para cargar un objeto complejo llamado Nodo ... bueno, no es tan complejo ... parece lo siguiente:

Un nodo tiene una referencia a EntityType que tiene un uno a muchos con propiedad que a su vez tiene un uno a muchos con PorpertyListValue

public class Node { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual EntityType Etype { get; set; } } public class EntityType { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual IList<Property> Properties { get; protected set; } public EntityType() { Properties = new List<Property>(); } } public class Property { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual EntityType EntityType { get; set; } public virtual IList<PropertyListValue> ListValues { get; protected set; } public virtual string DefaultValue { get; set; } public Property() { ListValues = new List<PropertyListValue>(); } } public class PropertyListValue { public virtual int Id { get; set; } public virtual Property Property { get; set; } public virtual string Value { get; set; } protected PropertyListValue() { } }

Lo que estoy intentando hacer es cargar el objeto Nodo con todos los objetos secundarios a la vez. Sin carga perezosa. La razón es que tengo miles de objetos Node en la base de datos y tengo que enviarlos por cable utilizando el servicio WCF. Me encontré con el problema de las clases SQL N + 1. Estoy usando Fluent Nhibernate with Automapping y NHibernate Profiler me sugirió usar FetchMode.Eager para cargar todos los objetos a la vez. Estoy usando la siguiente qyuery

Session.CreateCriteria(typeof (Node)) .SetFetchMode( "Etype", FetchMode.Join ) .SetFetchMode( "Etype.Properties", FetchMode.Join ) .SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )

O utilizando NHibernate LINQ

Session.Linq<NodeType>() .Expand( "Etype") .Expand( "Etype.Properties" ) .Expand( "Etype.Properties.ListValues" )

Cuando ejecuto cualquiera de las consultas anteriores, ambas generan una misma consulta con todas las combinaciones externas de la izquierda, que es lo que necesito. Sin embargo, por alguna razón, el IList de retorno de la consulta no se está cargando propiedad en los objetos. De hecho, el recuento de Nodos devuelto es igual al número de filas de la consulta, por lo que los objetos de los Nodos se repiten. Además, las propiedades dentro de cada Nodo se repiten, y también lo hacen los valores de lista.

Así que me gustaría saber cómo modificar la consulta anterior para devolver todos los nodos únicos con las propiedades y los valores de la lista dentro de ellos.

Gracias nabeel


Lo descubro yo mismo. La clave es usar SetResultTransformer () pasando un objeto de DistinctRootEntityResultTransformer como un parámetro. Así que la consulta ahora se ve como sigue

Session.CreateCriteria(typeof (Node)) .SetFetchMode( "Etype", FetchMode.Join ) .SetFetchMode( "Etype.Properties", FetchMode.Join ) .SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join ) .SetResultTransformer(new DistinctRootEntityResultTransformer());

Encontré la respuesta a mis preguntas a través de estos enlaces:

http://www.mailinglistarchive.com/html/[email protected]/2010-05/msg00512.html

http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx


SetResultTransformer con DistinctRootEntityResultTransformer solo funcionará para el objeto principal, pero las colecciones de IList se multiplicarán.


Terminé con algo como esto:

HasMany(x => x.YourList).KeyColumn("ColumnName").Inverse().Not.LazyLoad().Fetch.Join()

Solo asegúrese de seleccionar su entidad de esta manera, para evitar la duplicación debido a la unión:

session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.DistinctRootEntity).List<T>();