休眠自引用性能

本文关键字:性能 自引用 休眠 | 更新日期: 2023-09-27 17:56:27

我有一个看起来像这样的模型:

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 语句。有没有办法提高性能以在表上执行某种类型的联接或其他操作?

休眠自引用性能

您可以使用批处理大小来预取实例,从而大大减少查询数量。

映射(不确定同时是否支持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 => x.Children).AsSet()。SetAttribute("batch-size", "20")

查询

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

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

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

查询时,您可以急切地获取层次结构。您可以通过在查询中使用预先获取选项来执行此操作:

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

下到您要获取的级别。