2011-08-08 84 views
2

我確定我在這裏丟失了一些非常明顯的東西。
我想acheive是相當簡單 -爲查詢定義子查詢

我想一個查詢加載所有User•不用保溼他們PostsFollowers集合。
在另一個查詢中,我想要使用SubSelect來初始化這些集合。

在第二個查詢中使用Fetch(..)會發出左連接,這是我不想要的。
我可以像這樣(流利)的映射定義這些集合抓取策略:

.Not.LazyLoad() 
.Fetch.Subselect() 

這將導致第二個查詢運行我希望它的方式,但我不能關閉.Not.LazyLoad()爲第一個查詢(我試過.Fetch(u => u.Posts).Lazy,但似乎沒有做任何事情)。

我錯過了什麼?

+0

最近我已經完成了關於這些主題的大量研究,我想我可能會提供幫助。爲什麼要使用子選擇符有什麼特別的理由? – LeftyX

+0

這似乎是最好的選擇,性能明智。每個用戶都有很多帖子,所以不想用'Join'獲得笛卡爾產品,而且我有很多用戶,所以我不想讓你選擇N + 1。 –

+0

有幾個技巧可以避免笛卡爾產品。我會試着回答一個正確的答案。 – LeftyX

回答

3

我通常在我的映射中設置lazy=true(Ayende wrote about it),因爲我更喜歡控制我的代碼中的行爲。

這樣做你的關聯只有在你需要時纔會保溼。

var users = session.QueryOver<User>() 
    .List(); 

將加載所有的用戶,但不會加載自己的崗位,除非你訪問集合的元素:如果你想加載一些用戶和自己的崗位上,你可以簡單地做

var postTitle = users[0].Posts[0].Title; 

是這樣的:

Post posts = null; 

var users = session.QueryOver<User>() 
    .Where(x => x.Name == "Jamie") 
    .Inner.JoinAlias(t => t.Posts,() => posts) 
    .List(); 

或:

Post posts = null; 

var users = session.QueryOver<User>() 
    .Where(x => x.Name == "Jamie") 
    .Inner.JoinQueryOver(t => t.Posts,() => posts) 
    .List(); 

正如你可能已經使用取渴望注意到:

var users = session.QueryOver<User>() 
    .Where(x => x.Name == "Jamie") 
    .Fetch(x=>x.Posts).Eager 
    .List(); 

使用外連接,您不想要的。

上述兩個示例在您的評論中提到了一個問題。 如果你想避免笛卡爾乘積在結果與QueryOver你可以使用.TransformUsing(Transformers.DistinctRootEntity)

Post posts = null; 

var users = session.QueryOver<User>() 
    .Where(x => x.Name == "Jamie") 
    .Inner.JoinAlias(t => t.Posts,() => posts) 
    .TransformUsing(Transformers.DistinctRootEntity) 
    .List(); 

你可以找到更多的信息here

+0

使用'Inner'似乎是一個很好的方向,生成的SQL確實是我正在尋找的。但問題是'Posts'集合未被初始化。意義 - 在你的例子中調用代碼後,'NHibernateUtil.IsInitialized(user.Posts)'評估爲'false'。即使我在查詢中添加'.Fetch(x => x.Posts),Eager ''。任何想法爲什麼是這樣? –

+0

@sJhonny:我試過NHibernateUtil.IsInitialized我的示例代碼,它正常工作。你可以發佈一些代碼/ hbm? – LeftyX

+0

是的,你是對的。我的問題是我有一個抽象類型的集合。我已經提出了另一個更具挑戰性的問題。 http://stackoverflow.com/questions/7024348/fetching-strategies-for-collections-of-abstract-type –