2011-08-29 68 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,似乎没有任何效果。 –