1

假設我有一個名爲MyItem的實體。它可以包含在許多「父母」中,如SomeCollection和SomeOtherCollection。因爲它可以包含在許多父母中,並且由於我不希望MyItem知道父母,所以我想在MyItem中引用父母時沒有任何屬性。NHibernate實體鬆耦合

而且,像SomeCollection一樣,父母可以包含許多MyItems,我覺得我需要某種分頁方式來從父母中獲取孩子。這會讓我無法在SomeCollection中引用MyItems中的屬性。懶惰加載或不加載,它總是「全部或全部」(對吧?)。

我絕對需要一些引用MyItem實體和他們的父母,雖然在數據庫中的映射表的形式。

問題:

  • 如何創建此映射? 我可以有映射,還是應該將 關係保留在業務邏輯 中?
  • 如何查詢 哪些MyItem實體存在於 SomeCollection?我可以使用ICriteria只進行一次數據庫訪問嗎?
+0

偉大的問題。很棒,正是我想問的。 – Slavo

回答

1

Many-to-One
家長包含物業孩子,孩子可以從幾個家長聯繫起來。

class Parent 
{ 
    public virtual MyItem Child { get; set; } 
} 

<class name="Parent"> 
    <many-to-one name="Child" column="MyItemId" /> 
</class> 

Many-to-Many with a join table
家長包含的子集,孩子們可以從幾個家長聯繫起來。

class Parent 
{ 
    public virtual IList<MyItem> Children { get; set; } 
} 

<class name="Parent"> 
    <bag name="Children" table="parent_myitem"> 
     <key column="parentid" /> 
     <many-to-many class="MyItem" column="MyItemId" /> 
    <bag> 
</class> 

Criteria Querying

// find Parent with child named "foo". 
DetachedCriteria.For<Parent>() 
    .CreateAlias("Child", "c") 
    .Add(Restrictions.Eq("c.Name", "foo")); 

// find Parent with particular child 
DetachedCriteria.For<Parent>() 
    .Add(Restrictions.Eq("Child", child)); 


// find Parent with one of children named "foo". 
DetachedCriteria.For<Parent>() 
    .CreateAlias("Children", "c") 
    .Add(Restrictions.Eq("c.Name", "foo")); 

// find a "page" of children for a parent 
DetachedCriteria.For<Parent>() 
    .Add(Restrictions.Eq("Id", parent.Id)) 
    .CreateAlias("Children", "c") 
    .SetFirstResult(1041) 
    .SetMaxResults(20) 
    .GetExecutableCriteria(session) 
    .List<MyItem>(); 

這最後的查詢可能會或可能不會被更有效地利用只是延遲加載上首次訪問整個兒集合,然後索引到它後來的「做頁面」。這取決於您的數據和使用情況。

除非我先知道孩子的收藏會是巨大的,否則我會首先進入懶惰的負載路線。如果時間和profiling顯示嚴重緩慢,那麼我會切換到標準方法。

+0

這是我如何解釋你有關分頁的答案: 如果我將懶加載設置爲false,我不會使用父級的屬性,而是執行像「頁面」之類的條件來獲取父級的子級頁面。 另一種方法是對批量大小使用延遲加載。然後,如果我使用Children屬性,則會一次提取「批量」孩子。因此,對於批次數爲20的孩子,如果孩子數量爲41到60,則會導致三次到數據庫,每次導致20個項目。 這是對你答案的正確解釋嗎? – Kristoffer

+0

@Kristoffer使用lazy =「true」,如果你不想讓孩子加載Parent。 –

+0

@Kristoffer我剛剛運行了一些測試,並且我的建議對於批處理大小和集合是錯誤的。答案已經相應更新。 –

0

我有像你這樣的情況。我有配置類,可以是全局配置,項目特定配置或用戶特定配置。我所做的是這樣的:

  1. 我映射家長像我通常會在任何情況下,所有可能的父母(除全球性的,它意味着適用於所有所以沒有父母)
< class name="ConfigurationDomain" table="configuration"> 
    < property name="ProjectId" column="project_id" type="int" insert="false" update="false" /> 
    < property name="UserId" column="user_id" type="int" insert="false" update="false" /> 
    < many-to-one name="Project" column="project_id" lazy="false" /> 
    < many-to-one name="User" column="estimator_id" lazy="false" /> 
< /class> 
  • 我的配置作爲集合映射在每一個可能的父母
  • < class name="UserDomain" table="user"> 
        < set name="ConfigurationList" lazy="true" cascade="all-delete-orphan"> 
         < key column="user_id" /> 
         < one-to-many class="ConfigurationDomain" /> 
        < /set> 
    < /class> 
    
    < class name="ProjectDomain" table="user"> 
        < set name="ConfigurationList" lazy="true" cascade="all-delete-orphan"> 
         < key column="project_id" /> 
         < one-to-many class="ConfigurationDomain" /> 
        < /set> 
    < /class> 
    

    就像那樣,它對我有用。如何訪問配置,例如,用戶ID爲55這是:

    我不使用someUser.ConfigurationList,因爲它很慢。我只映射父,這樣我可以在HQL做到這一點(它的速度更快):

    select c from ConfigurationDomain c where c.UserId=55 
    

    而獲取全局配置我這樣做:

    select c from ConfigurationDomain c where (c.UserId IS NULL) and (c.ProjectId IS NULL) 
    

    經過思考,我覺得你可以如果您決定使用HQL,甚至可以刪除集合映射。

    注意:我在NHibernate的早期階段使用過Criteria,但後來我發現HQL對我來說有點強大,其他人可能會對此有不同的看法。