¿Cómo cargar asociaciones con ansias sin duplicación en NHibernate?

Resuelto The Light asked hace 10 años • 0 respuestas

Necesitaría cargar una lista de objetos muy grandes con tantos hijos e hijos de niños. ¿Cuál es el mejor enfoque a seguir?

Estoy usando la base de datos Oracle 11g y escribí el siguiente método, pero da como resultado un producto cartesiano (resultados duplicados):

 public IList<ARNomination> GetByEventId(long eventId)
        {
            var session = this._sessionFactory.Session;

            var nominationQuery = session.Query<ARNomination>().Where(n => n.Event.Id == eventId);

            using (var trans = session.Transaction)
            {
                trans.Begin();

                // this will load the Contacts in one statement
                nominationQuery
                    .FetchMany(n => n.Contacts)
                    .ToFuture();

                // this will load the CustomAttributes in one statement
                nominationQuery
                    .FetchMany(n => n.CustomAttributes)
                    .ToFuture();

                // this will load the nominations but joins those two tables in one statement which results in cartesian product
                nominationQuery
                    .FetchMany(n => n.CustomAttributes)
                    .FetchMany(n => n.Contacts)
                    .ToFuture();

                trans.Commit();
            }

            return nominationQuery.ToList();
        }
The Light avatar Jan 07 '14 18:01 The Light
Aceptado

Obtener colecciones es una operación difícil. Tiene muchos efectos secundarios (como te habrás dado cuenta cuando se hayan obtenido más colecciones) . Pero incluso al recuperar una colección, estamos cargando muchas filas duplicadas.

En general, para cargar colecciones, sugeriría utilizar el procesamiento por lotes. Esto ejecutará más consultas SQL... pero no tantas, y lo que es más importante, puedes realizar paginación en la lista raíz ARNomination.

Ver: 19.1.5. Utilizando la recuperación por lotes puede encontrar más detalles.

Tienes que marcar tus colecciones y/o entidades con un atributo batch-szie="25".

XML:

<bag name="Contacts" ... batch-size="25">
...

fluido:

HasMany(x => x.Contacts)
  ...
  .BatchSize(25)

Por favor, consulte algunos argumentos aquí:

  • NHibernate QueryOver con Fetch genera múltiples consultas SQL y accesos a la base de datos
  • ¿Es esta la forma correcta de cargar colecciones secundarias en NHibernate?
  • https://stackoverflow.com/q/18419988/1679310
Radim Köhler avatar Jan 07 '2014 11:01 Radim Köhler

Estoy de acuerdo con @RadimKöhler, tan pronto como deseas cargar más de una colección, siempre aparece un producto cartesiano. Para seleccionar un tamaño de lote adecuado, probablemente elegiría que este sea el mismo que page sizeme parece correcto... (aunque no hay evidencia de por qué)

Hay otra técnica que puede considerar más adecuada y es leer esta publicación de blog de Ayende que le muestra cómo puede enviar dos consultas futuras al mismo tiempo para cargar varias colecciones; ese trabajo del alma es cargar cada colección individualmente. .

Sin embargo, sea cual sea la ruta que tomes, te sugiero que analices los resultados con un generador de perfiles para ver cuál funciona mejor para ti...

Rippo avatar Jan 07 '2014 13:01 Rippo