nhibernate multi-query

NHibernate Multiquery para carga ansiosa sin uniones



multi-query (2)

¿Es posible usar un multiquery y tener dos consultas hql devolviendo dos conjuntos diferentes de entidades donde uno de los conjuntos se utiliza en el otro y que la sesión "corrige" esto a través del primer nivel de caché?

Ej. Escenario (un tonto y podría resolverse con combinaciones)

public class Room { ... public virtual ISet<Bookings> Bookings {get;set;} public virtual bool IsAvailible {get;set;} ... } public class Booking { ... }

Después de ejecutar un multicriterio con dos hql''s:

  1. devolviendo todas las habitaciones donde IsAvailible = true
  2. devolviendo todas las reservas que tienen una habitación que tiene una habitación que IsAvailible

al acceder a una sala desde el resultado y sus reservas, quiero que se resuelvan desde el segundo conjunto de resultados a través del primer nivel de la memoria caché de la sesión y evitando n + 1.


En general, NHibernate puede usar el caché para "combinar" los resultados de las consultas ejecutadas a través de Multiquery. Sin embargo, debe tenerse en cuenta que esto generalmente solo se aplica a los casos en que las colecciones perezosas se cargan sin restricciones de ningún tipo.

Ejemplos:

Invoice iAlias = null; InvoiceDetails idAlias = null; // Base-Query: get Invoices with certain condition var invoices = session.QueryOver<Invoice>() .Where(i => i.Number == "001") .Future<Invoice>(); // Option 1: this will still cause N+1 if we iterate through invoices, // because it doesn''t know better var invoicedetails = session.QueryOver<InvoiceDetails>() .JoinAlias(a => a.Invoice, () => iAlias) .Where(() => iAlias.Number == "001") .Future<InvoiceDetails>(); // Option 2: this will still cause N+1 if we iterate through invoices, // because we limited the possible results using a where-condition var invoices2 = session.QueryOver<Invoice>() .Left.JoinAlias(i => i.Details, () => idAlias) .Where(i => i.Number == "001") .And(() => idAlias.Quantity > 5) .Future<Invoice>(); // Option 3: this will work without N+1, because we don''t use a filter // -> NHibernate will use the collection in cache var invoices3 = session.QueryOver<Invoice>() .Left.JoinAlias(i => i.Details, () => idAlias) .Where(i => i.Number == "001") .Future<Invoice>(); foreach (Invoice i in invoices) { int count = i.Details.Count; }

Si comentamos dos de las tres opciones y ejecutamos el código, veremos que solo la opción 3 evitará una N + 1, las otras dos seguirán cargando los InvoiceDetails para cada Invoice en el bucle.

Por supuesto, este es un ejemplo muy simple y es obvio que la Opción 3 también podría ejecutarse sin la consulta base y aún así devolver el mismo resultado, pero espero que entiendas la idea.

En el caso donde cargamos dos conjuntos diferentes de entidades, es decir, la clase raíz es diferente a la Opción 1, esta "combinación" probablemente no funcionará.

Lo siento, si utilicé QueryOver en lugar de HQL, pero se aplican las mismas reglas.


Gyus, ten en cuenta que a veces puedes tener problemas similares porque LeftOuterJoin no está configurado.

.JoinAlias ​​(x => x.Prop, () => propAlias, JoinType.LeftOuterJoin)