2011-03-28 24 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