2011-03-28 42 views
2

我可能会使用Future<T>方法,但我在理解如何优化它的使用方面有很多麻烦。所以这是我的简单例子。nHibernate未来<T>,关于加载顺序的困惑

三个对象,MemberPlayerCharacter

Member { 
    Player Player { get; set; } 

Player { 
    IList<Character> Characters { get; set; } 
} 

因此,基本上,一个成员也是一个球员,一个球员有许多字符。够简单。 (这个抽象的原因是为了保持Member轻巧,所以它只能用于身份验证和角色,其中更大量的数据具有附加到Player类中使用。)

那么,我有一个方法,我想要查询Player所有的Character。所以我下面的查询设置...

 session.QueryOver<Player>() 
      .Fetch(context => context.Characters).Eager 
      .Take(1) 
      .Future<Player>(); 

     session.QueryOver<Character>() 
      .Future<Character>() 
      .Take(10); 

     return session.QueryOver<Member>() 
      .Where(model) 
      .Fetch(context => context.Player).Eager 
      .List() 
      .Take(1) 
      .SingleOrDefault() 
      .Player; 

我在这里的想法是,从我的理解有关的方式Future<T>作品(可能是遥远的,它会急于负载Player(1:1 ),它将在相同的数据库旅程中执行查询IList<Character>,限制为10次结果,每次旅行只需要1个玩家,每次游览1个会员,每次游览最多10个字符。然而nhProf告诉我我正在使用无限的请求,有人可以向我解释这里发生了什么吗?我只是误解了这些方法的工作原理吗?或者任何人都可以提供一个例子,它是有点更可行?我不明白HQL,所以我不能使用CreateCriteria方法。

回答

10

在你的问题的三个查询将做到以下几点:

查询1将采取的第一个球员可以在数据库中查找,没有任何地方条件。

查询2将采取它能找到的前十个字符,同样没有任何条件。

查询3将执行三个查询,并将与您的where-condition匹配的第一个成员以及关联的Player一起,并返回成员的播放器。

如果你想遍历玩家角色NHibernate会再次击中数据库,因为没有角色已经被加载。

你的例子可以在一个单一的查询来完成,而不期货这样的:

System.Linq.Expressions.Expression<Func<Member, bool>> model = m => m.Id == 1; 
Member mAlias = null; 
Player pAlias = null; 
Character cAlias = null; 

Member member = session.QueryOver<Member>(() => mAlias) 
    .JoinAlias(m => m.Player,() => pAlias) 
    .Left.JoinAlias(() => pAlias.Characters,() => cAlias) 
    .Where(model) 
    .List().FirstOrDefault(); 

这里是可以表现出更好的东西期货可以做一个例子。查询的目标是获取id = 1的客户及其所有订单和订单的详细信息和预订。现在

Class diagram

,如果我们要与他们的详细信息和预订订单加载一起生成的查询会得到我们的笛卡尔乘积:count(Details) * count(Bookings)

int id = 1; 
// define Aliases to use in query and be able to reference joined entities 
Customer cAlias = null; 
Order oAlias = null; 
OrderDetails odAlias = null; 
Booking bAlias = null; 

// get the Customer and his Orders 
var customers = session.QueryOver<Customer>(() => cAlias) 
    .Left.JoinAlias(o => o.Orders,() => oAlias) 
    .Where(c => c.Id == id) 
    .Future<Customer>(); 

// get the Orders and their Details 
var orders = session.QueryOver<Order>(() => oAlias) 
    .JoinAlias(o => o.Customer,() => cAlias) 
    .Left.JoinAlias(() => oAlias.Details,() => odAlias) 
    .Where(() => cAlias.Id == id) 
    .Future<Order>(); 

// get the Orders and their Bookings 
var orders2 = session.QueryOver<Order>(() => oAlias) 
    .JoinAlias(o => o.Customer,() => cAlias) 
    .Left.JoinAlias(() => oAlias.Bookings,() => bAlias) 
    .Where(() => cAlias.Id == id) 
    .Future<Order>(); 

var list = customers.ToList(); 
Customer customer = list.FirstOrDefault(); 

Order o1 = customer.Orders.FirstOrDefault(); 
// iterate through the Details 
// normally this would cause N+1 selects, here it doesn't, because we already loaded 
foreach (OrderDetails od1 in o1.Details) 
{ 
    decimal d = od1.Quantity; 
} 

我所有的映射与延迟加载工作,我没有在这些查询中指定急切的加载。但是,当我运行代码时,在一次往返中只有三个SQL查询没有笛卡尔积。这就是期货的美妙之处。

+1

这真的很好,真的很有用。我很难找到很多解释未来如何运作的东西,我所找到的每一个资源都假设你只是在本质上'理解'它们是什么。 Ayende的博客有一个非常好的帖子,但它使用了很多HQL,并且这个例子对于我的经验不足的人来说完全没有冗长。 – Ciel 2011-03-29 13:10:14

+0

即使使用此代码,我仍被告知我正在使用“未绑定结果集”。但我不明白为什么。 – Ciel 2011-03-29 13:43:07

+0

@Ciel准确的代码是什么?没有期货的查询或三个查询的例子?您是否已将.SetMaxResults()添加到上面的查询中?对不起,我还没有使用NHProf,所以我无法试验。 – 2011-03-29 14:31:37