2011-08-29 70 views
1

我有2個實體:避免重複父對象與屬性-REF映射時

實體A

public class EntityA 
     { 
      protected IList<EntityB> _bList = new List<EntityB>(); 

      virtual public int Id { get; set; } 
      virtual public int ExtId { get; set; } 


      public virtual void AddB(EntityB b) 
      { 
       if (!_bList.Contains(b)) _bList.Add(b); 
       b.A = this; 
       b.ExtId = this.ExtId; 
      } 

      public virtual void RemoveB(EntityB b) 
      { 
       _bList.Remove(b); 
      } 

      public virtual IList<EntityB> BList 
      { 
       get { return _bList.ToList().AsReadOnly(); } 
      } 
     } 

實體的映射

<?xml version="1.0" encoding="utf-8" ?> 
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true"> 
     <class name="hibernate.domain.mappings.EntityA, hibernate.domain" lazy="true"> 
     <id name="Id"> 
      <generator class="native" /> 
     </id> 
     <property type="int" name="ExtId" column="[ExtId]" /> 
     <bag 
      name="BList" 
      table="EntityB" 
      cascade="all" 
      lazy="true" 
      inverse="true" 
      access="field.camelcase-underscore" 
      optimistic-lock="false" 
      > 
      <key column ="ExtId" property-ref="ExtId" /> 
      <one-to-many class="hibernate.domain.mappings.EntityB, hibernate.domain" /> 
     </bag> 
    </hibernate-mapping> 

實體B

 public class EntityB 
     { 
      protected EntityA _a; 

      virtual public int Id { get; set; } 
      virtual public int ExtId { get; set; } 
      virtual public EntityA A 
      { 
       get { return _a; } 
       set { _a = value; } 
      } 
     } 

實體B映射

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true"> 
    <class name="hibernate.domain.mappings.EntityB, hibernate.domain" lazy="true"> 
    <id name="Id"> 
     <generator class="native" /> 
    </id> 
    <property type="int" name="ExtId" column="[EXTID]" /> 
    <many-to-one 
      name = "A" 
     property-ref ="ExtId" 
      not-null="true" 
      class = "hibernate.domain.mappings.EntityA, hibernate.domain" 
     access="field.camelcase-underscore" 
      cascade = "save-update" 
      fetch="select" 
      insert = "false" 
     lazy = "false" 
      update = "false" 
     column="ExtId" 
     /> 
    </class> 
</hibernate-mapping> 

問題是,當我加載EntityA的對象,試圖讓BList的計數,它將實現每EntityB一個SQL列表中獲取它的EntityA參考,但EntityA每個EntityB會我先裝入的原始實體。當entityA內部有大量的entityB時,這已經成爲一個很大的性能瓶頸。數據庫是遺留的,它與一些遺留應用程序一起使用,所以更改數據庫結構不是一種選擇。並且使用二級緩存也不是一種選擇,因爲它會在使用原始SQL的遺留代碼運行時導致系統失敗。任何人都可以在不改變數據庫結構的情況下提出解決這個問題

回答

1

的問題是,緩存只能基於主鍵。如果它由其他屬性鏈接,則不知道它是否已經加載並重新加載。

this post by ayende中有一個暗示,二級緩存可能會考慮natural-id。我知道你不想要它。它甚至不能確定它在這種情況下工作(ayende對自然id使用明確的過濾器)。

您可能會嘗試將EXTID列映射爲NH中的主鍵,並將Id作爲生成的屬性進行映射......當然存在您得到其他問題的風險。

當什麼都不能實現時,您需要執行查詢以獲取所需的確切數據。例如:

select a, size(a.BList) 
from EntityA a 

這當然不好笑,當然,你放棄了使用實體作爲POCO的自然方式。

+0

雖然這不是一個直接的解決方案,但似乎沒有其他方法可以解決問題。所以我接受這個答案。 –

0

您可以在<many-to-one name = "A">改變fetch="select"fetch="join"那麼它會發出一個連接時,取燒烤和不必須選擇N + 1

+0

感謝您的回答。它仍然每B執行SQL,似乎沒有任何效果。 –