2013-07-13 73 views
3

使用LINQ-to-NHibernate有什麼方法可以縮小FetchMany()的返回值?LINQ-to-NHibernate的Where子句FetchMany?

考慮下面的類結構

public class Foo 
{ 
    public virtual int Id { get; set; } 
    public virtual IList<Bar> Bars { get; set; } 
} 
public class Bar 
{ 
    public virtual string Description { get; set; } 
} 

我怎樣才能做到這一點:

session.Query<Foo>() 
    .Where(foo => foo.Id > 30) 
    .FetchMany(foo => 
    foo.Bars.Where(bar => bar.Description.StartsWith("x"))); 

和NHibernate將返回所有Foo的一個ID> 30,併爲那些Foo的所有附加酒吧的其中酒吧的描述以字母'x'開始?

我發現一些文章使用舊的QueryOver()的東西,但我明確地想要使用NHibernate的LINQ提供程序。

任何想法?


更新

我想我需要澄清我想要的結果。

<Foo Id="1"> 
    <Bar Description="x1"/> 
    <Bar Description="b1"/> 
</Foo> 
<Foo Id="31"> 
    <Bar Description="x2"/> 
    <Bar Description="x3"/> 
    <Bar Description="b2"/> 
</Foo> 
<Foo Id="32"> 
    <Bar Description="b3"/> 
</Foo> 

從上面我希望以下結果中列出的數據

<Foo Id="31"> 
    <Bar Description="x2"/> 
    <Bar Description="x3"/> 
</Foo> 
<Foo Id="32"/> 

附加Where子句應只在酒吧的工作!它不應該進一步縮小Foo的名單!只需減少FetchMany()返回的內容即可。

+0

它現在返回什麼? –

+0

@GertArnold現在,查詢甚至不會編譯...如果我刪除第二個Where子句,它將返回所有Foo的一個Id> 30加上所有酒吧附加到他們每個人。我無法找到一種方法來對「FetchMany()」的調用返回的內容進行過濾。 –

回答

0

也許不是究竟是你以後怎麼樣,但肯定值得考慮的是NHibernate.CollectionQuery庫。

它允許您查詢使用Linq的實體上的未初始化的NHibernate集合 - 但需要額外的查詢/往返才能獲得它們(與FetchMany不同,它可以在同一往返中捕獲整個集合)。

+0

它會產生SELECT N + 1問題。 – hazzik

+0

我們有一個相當複雜的對象層次結構。手動查詢每個集合會增加太多開銷(包括代碼和往返次數)。但它看起來像一個有趣的項目。 –

0

您將需要從子對象到父對象的引用。

var result = from foo in session.Query<Foo>().FetchMany(f => f.Bars) 
      from bar in session.Query<Bar>() 
      where foo.Id == bar.FooId && // FooId is missing in your entity 
        foo.Id > 30 
        bar.Description.StartsWith("x") 
      select foo; 
+0

我們的模型中沒有Bar到Foo的「back-link」,我們不打算僅爲這些查詢引入一個。 –

1

我相當肯定你的運氣與當前LINQ提供程序的 - 但對於非LINQ(和交叉)選項,你可能想看看包括filter功能在NHibernate中 - 這可能是在大規模/複雜項目中實現這個最好的選擇。

1
var query = from foo in session.Query<Foo>() 
      where foo.Id >30 
      from bar in foo.Bars 
      where bar.Description.StartsWith("x") 
      select new { Id = foo, Bar = bar}; 
var results = query.ToList().ToLookup(x => x, x => x.Bar); 
foreach(var foo in results.Keys) 
{ 
    var barsWhichStartWithX = results[foo]; 
    //DO STUFF 
} 

雖然這可能會產生低效的SQL(我不使用nHibernate,所以我不知道)。你也可以試試這個......上面也會漏掉沒有酒吧的foos。

var foosQuery = session.Query<Foo>().Where(foo => foo.Id > 30); 
var foos = foosQuery.Future(); 
var barsQuery = from f in foosQuery 
       from bar in foo.Bars 
       select new { Id = foo.Id, Bar = bar}; 
var foosDict = foos.ToDictionary(x => x.Id); 
var bars = barsQuery.ToList().ToLookup(x => foosDict[x.Id], x => x.Bar); 
foreach(var foo in foos) 
{ 
    var barsWhichStartWithX = bars[foo]; 
    //DO STUFF 
}