2010-06-29 173 views
22

我有一個要求加載一個複雜對象調用節點 ...好它不是那麼複雜......它看起來像如下: -預先加載使用功能NHibernate/NHibernate的與自動映射

一個節點具有的EntityType具有一對多屬性其又具有一對多PorpertyListValue

0的參考
public class Node 
{ 
    public virtual int Id 
    { 
     get; 
     set; 
    } 

    public virtual string Name 
    { 
     get; 
     set; 
    } 

    public virtual EntityType Etype 
    { 
     get; 
     set; 
    } 

} 


public class EntityType 
{ 
    public virtual int Id 
    { 
     get; 
     set; 
    } 

    public virtual string Name 
    { 
     get; 
     set; 
    } 

    public virtual IList<Property> Properties 
    { 
     get; 
     protected set; 
    } 

    public EntityType() 
    { 
     Properties = new List<Property>(); 
    } 
} 

public class Property 
{ 
    public virtual int Id 
    { 
     get; 
     set; 
    } 

    public virtual string Name 
    { 
     get; 
     set; 
    }   

    public virtual EntityType EntityType 
    { 
     get; 
     set; 
    } 

    public virtual IList<PropertyListValue> ListValues 
    { 
     get; 
     protected set; 
    } 

    public virtual string DefaultValue 
    { 
     get; 
     set; 
    } 

    public Property() 
    { 
     ListValues = new List<PropertyListValue>(); 
    } 
} 


public class PropertyListValue 
{ 
    public virtual int Id 
    { 
     get; 
     set; 
    } 

    public virtual Property Property 
    { 
     get; 
     set; 
    } 

    public virtual string Value 
    { 
     get; 
     set; 
    } 

    protected PropertyListValue() 
    { 
    } 
} 

我試圖做的是一次加載所有子對象的節點對象。沒有延遲加載。原因是我有數以千計的數據庫中的節點對象,我必須通過使用WCF服務的線路發送它們。我遇到了類SQL N + 1問題。我將Fluent Nhibernate與Automapping結合使用,並且NHibernate Profiler建議我使用FetchMode.Eager一次加載整個對象。我現在用的是以下qyuery

 Session.CreateCriteria(typeof (Node)) 
      .SetFetchMode("Etype", FetchMode.Join) 
      .SetFetchMode("Etype.Properties", FetchMode.Join) 
      .SetFetchMode("Etype.Properties.ListValues", FetchMode.Join) 

或當我運行任何上述查詢使用NHibernate LINQ

 Session.Linq<NodeType>() 
     .Expand("Etype") 
     .Expand("Etype.Properties") 
     .Expand("Etype.Properties.ListValues") 

,他們都產生了所有的左外同一個單一查詢聯接,這是什麼我需要。但是,由於某種原因,返回的IList從查詢中沒有被加載到對象中。事實上,返回的節點計數等於查詢的行數,因此節點對象會重複。而且,每個節點中的屬性都會重複,Listvalues也會重複。

所以我想知道如何修改上面的查詢來返回其中的屬性和列表值的所有唯一節點。

感謝 納比爾

+0

在谷歌我發現了DistinctRootEntityResultTransformer但 只解決了Root對象的問題。我仍然在子集合中獲得 重複項。 返回列表中的每個根對象在具有同一實體的多個實例的子集 集合中都有一些奇怪的笛卡兒積。任何想法? 等待 Nabeel – nabeelfarid 2010-06-30 11:39:05

+1

我想我找到了解決方案,但我想知道它的 是否正確。 根對象(Node)內的子集合(EType.Properties,Etype.Properties.ListValues) 是IList。我在文檔 中看到IList可以包含重複項,所以如果我將IList更改爲ISet/ ICollection,那麼查詢不會在子集合中加載 中的重複實例。 但是這個解決方案需要大量的重構。我想知道 如果有一種方法可以使用IList爲兒童 集合實現相同效果嗎? 等待, Nabeel – nabeelfarid 2010-06-30 15:31:20

+1

我有同樣的問題(使用Fetchmode.Eager)。我在NHibernate中對此非常失望。我寧願有一個錯誤比錯誤的數據。 – UpTheCreek 2011-01-17 14:00:18

回答

13

我找出自己。關鍵是使用SetResultTransformer()傳遞DistinctRootEntityResultTransformer作爲參數的對象。所以查詢現在看起來如下

Session.CreateCriteria(typeof (Node)) 
    .SetFetchMode("Etype", FetchMode.Join) 
    .SetFetchMode("Etype.Properties", FetchMode.Join) 
    .SetFetchMode("Etype.Properties.ListValues", FetchMode.Join) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

我發現這些鏈接指向的回答我的問題:

http://www.mailinglistarchive.com/html/[email protected]/2010-05/msg00512.html

http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx

+4

+1,但哇,這是醜陋的。這看起來如此混亂 - 我對Nibernate並沒有留下深刻的印象。爲什麼我們需要改變結果? NH似乎並沒有做好它的工作。 – UpTheCreek 2011-01-17 14:06:00

21

每個映射必須有延遲加載關閉

在節點地圖:

Map(x => x.EntityType).Not.LazyLoad(); 
在EnityType地圖

Map(x => x.Properties).Not.LazyLoad(); 

等.. 。

另請參閱NHibernate Eager loading multi-level child objects一次性預先加載

補充:有關SQL N + 1

附加信息:

http://nhprof.com/Learn/Alerts/SelectNPlusOne

+2

感謝您的迴應Tim, 嗯,我不想在映射中設置.Not.LazyLoad(),因爲它會變成默認行爲,並且在我的應用程序中我有一個wcf服務,需要將數據傳遞給客戶端和我想要在單個查詢中一次加載所有數據以避免SQL N + 1場景(http://nhprof.com/Learn/Alerts/SelectNPlusOne)。應用程序的其餘部分不需要預先加載。因此,任何想法如何解決這種情況? – nabeelfarid 2010-06-30 08:18:29

+1

另外我的理解是.Not.LazyLoad不能解決SQL N + 1問題。 Fro mNhibernate剖析器我已經注意到,雖然它一次加載所有對象圖,但它仍然會生成多個查詢,每個引用/ hasmany對象的查詢,我不想要,因爲我擁有多個節點, entitytypes和屬性,我不希望thosands獨特的查詢生成。 Nabeel – nabeelfarid 2010-06-30 10:27:16

+0

我以爲你想要這樣映射。我添加了一個指向另一個問題的鏈接,該鏈接顯示在特定實例中進行加載。我認爲這會幫助你創建一個連接。如果沒有,您可以查看正確的存儲過程並將其映射爲命名查詢。請參閱http://stackoverflow.com/questions/1637862/fluent-nhibernate-and-stored-procedures中的原始海報代碼,以獲得 – 2010-07-01 12:19:20

4

SetResultTransformer與DistinctRootEntityResultTransformer將只對主要對象工作,但IList館藏將會成倍增加。

+0

這是正確的。一個人使用的ISet或ICollection的 – nabeelfarid 2011-01-06 15:42:15

+0

你將如何使用的ISet或ICollection的? – 2013-07-09 21:34:00

8

我結束了這樣的事情:

HasMany(x => x.YourList).KeyColumn("ColumnName").Inverse().Not.LazyLoad().Fetch.Join() 

只要確保選擇實體像這樣,爲了避免重複,由於加入:

session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.DistinctRootEntity).List<T>(); 
+0

你也可以參考嗎? – aggietech 2015-01-23 20:32:03