Nhibernate自我参考表现

时间:2011-05-12 12:23:10

标签: c# .net nhibernate

我的模型看起来像这样:

public class ComponentAttributeDto
{
    public virtual long ComponentAttributeId { get; set; }
    public virtual ComponentAttributeDto ParentComponentAttributeDto { get; set; }
    public virtual string ComponentAttributeName { get; set; }
    public virtual string Value { get; set; }
    public virtual DataType DataType { get; set; }
    public virtual IList<ComponentAttributeDto> ChildComponentAttributes { get; set; }
}

使用映射文件:

public class ComponentAttributeMapping : ClassMap<ComponentAttributeDto>
{
    public ComponentAttributeMapping()
    {
        Table("ComponentAttributes");

        Id(x => x.ComponentAttributeId)
            .GeneratedBy.Identity();

        References(x => x.ParentComponentAttributeDto)
            .Column("ParentComponentAttributeId");

        HasMany(x => x.ChildComponentAttributes)
            .Fetch.Select()
            .Inverse()
            .Cascade.AllDeleteOrphan()
            .KeyColumn("ParentComponentAttributeId");

        Map(x => x.ComponentAttributeName)
            .Length(50);

        Map(x => x.Value)
            .Length(1500);

        Map(x => x.DataType)
            .Length(20);
    }
}

当使用大约4级深度的大型数据集加载时,性能非常糟糕。运行探查器时,我注意到它是为表中要查找的数据的每个值执行一个select语句。有没有办法可以提高性能,以便在表格或其他方面进行某种类型的连接?

3 个答案:

答案 0 :(得分:1)

您可以使用batch-size预取实例,这会大大减少查询次数。

映射(不确定Fluent是否同时支持):

HasMany(x => x.ChildComponentAttributes)
            .Fetch.Select()
            .SetAttribute("batch-size", "20")
            .Inverse()
            .Cascade.AllDeleteOrphan()
            .KeyColumn("ParentComponentAttributeId");

如果您有Root属性,则可以立即查询整个树。

public class ComponentAttributeDto
{
  public virtual ComponentAttributeDto ParentComponentAttributeDto { get; private set; }
  public virtual ComponentAttributeDto Root 
  { 
     get 
     {
       if (ParentComponentAttributeDto == null) 
       {
         return this;
       }
       else 
       {
         return ParentComponentAttributeDto.Root;
       }
     }
     private set
     { /* just for NH to call it */ }
  }
  // ....
}

HasMany(x =&gt; x.Children).AsSet()。SetAttribute(“batch-size”,“20”)

查询

session.CreateQuery(
@"from ComponentAttributeDto
where Root = :root"
  .SetEntity(root);

实际上应该只导致一个查询。不确定NH是否实际上不对列表执行查询(ChildComponentAttributes),但值得一试。

答案 1 :(得分:0)

您是否一次需要整个数据结构?通常当我遇到这个问题时,我只是从nHibernate中取走映射处理并自己处理它。为名为getChildren()的类创建一个方法,让它在调用时运行查询。如果要添加子记录,则添加另一个名为addChild()的方法,并使用它自己的父ID进行实例化。

答案 2 :(得分:0)

您可以在查询时急切地获取层次结构。您可以使用查询中的eager fetch选项执行此操作:

Session.QueryOver<ComponentAttributeDto>
       .Fetch(a => a.ChildComponentAttributes).Eager

降低到你想要的等级。