Вообще говоря, NHibernate может использовать кеш для «объединения» результатов запросов, выполненных через Multiquery.Однако следует отметить, что это обычно относится только к случаям, когда ленивые коллекции загружаются без каких-либо ограничений.
Примеры:
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;
}
Если мы закомментируем два из трех вариантов ивыполнив код, мы увидим, что только вариант 3 будет препятствовать N + 1, другие два все равно будут загружать InvoiceDetails
для каждого Invoice
в цикле.
Конечно, это очень простопример и очевидно, что вариант 3 также может быть выполнен без Base-запроса и по-прежнему возвращать тот же результат, но я надеюсь, что вы поняли.
В случае, когда мы загружаем два разных набора сущностей,т.е. корневой класс отличается от варианта 1, это «объединение», скорее всего, не будет работать.
Извините, если я использовал QueryOver вместо HQL, но применяются те же правила.