NHibernate Multiquery用于没有连接的急切加载

时间:2011-04-12 11:33:21

标签: nhibernate multi-query

是否可以使用多个查询并且有两个hql查询返回两个不同的实体集,其中一个集合在另一个集合中使用,并且会话通过第一级缓存“修复”这个?

E.g。场景(一个愚蠢的,它可以用连接解决)

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

public class Booking
{
  ...
}

执行带有两个hql的多标准:

  1. 归还所有房间 IsAvailible = true
  2. 归还所有预订房间的房间,房间是可以使用的房间
  3. 从结果及其预订中访问房间时,我希望通过会话的 firstlevel cache 从第二个结果集中解析它们,并避免使用n + 1.

2 个答案:

答案 0 :(得分:7)

一般来说,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在循环中。

当然这是一个非常简单的例子,很明显,Option 3也可以在没有Base-query的情况下执行,但仍然会返回相同的结果,但我希望你能得到这个想法。

在我们加载两组不同的实体的情况下,即根类与选项1中的不同,这种“组合”很可能不起作用。

很抱歉,如果我使用的是QueryOver而不是HQL,但适用相同的规则。

答案 1 :(得分:0)

Gyus,请记住,有时候你可能会遇到类似的问题 LeftOuterJoin未设置。

  

.JoinAlias(x =&gt; x.Prop,()=&gt; propAlias,JoinType.LeftOuterJoin)