【问题标题】:Does anyone know why I'm getting this warning from NHibernate/NH Profiler?有谁知道为什么我会从 NHibernate/NH Profiler 收到此警告?
【发布时间】:2012-07-13 23:13:51
【问题描述】:

“为fully_qualified_type_name 禁用惰性属性获取,因为它不支持实体级别的惰性”。

NH Profiler 报告了此警告,因此,我遇到了可怕的 SELECT N + 1 副作用。因此,如果返回 2200 个子组实体,则会执行一个附加查询来检索每个 InvoicePreference 实体(总共 2201 个查询)。这种关系似乎是导致问题的原因。

以下是相关实体及其各自的映射。

实体 1

public class Subgroup : Entity
{
     public virtual string GroupNumber { get; set; }

     public virtual string RUSNumber { get; set; }

     public virtual string REANumber { get; set; }

     public virtual string CustomerType { get; set; }

     public virtual string Name { get; set; }

     public virtual IList<IndividualEmployment> Employees { get; set; }

     public virtual IList<BenefitsAdministrator> Administrators { get; set; }

     public virtual InvoicePreference InvoicePreference { get; set; }
}

实体 2

public class InvoicePreference : IEntity
{
    public virtual Guid Id { get; set; }

    public virtual Guid SubgroupId { get; set; }

    public virtual bool PaperlessNotifications { get; set; }
}

映射 1

public static AutoPersistenceModel ConfigureSubGroup(this AutoPersistenceModel 
autoPersistenceModel)
{
    return autoPersistenceModel.Override<Subgroup>(map =>
    {
        map.Table("SubgroupV");

        map.Id(s => s.Id).Column(SubGroupPrimaryKeyColumn);

        map.Map(s => s.CustomerType, "BAS_Customer_Type");
        map.Map(s => s.RUSNumber, "BAS_RUS_Number");
        map.Map(s => s.GroupNumber, "BAS_Group_Number");
        map.Map(s => s.REANumber, "BAS_REA_Number");

        map.HasMany(s => s.Administrators).KeyColumn(SubGroupPrimaryKeyColumn);
        map.HasMany(s => s.Employees).KeyColumn(SubGroupPrimaryKeyColumn);
        map.HasOne(s => s.InvoicePreference).PropertyRef(i => i.SubgroupId);
    });
}

映射 2

public static AutoPersistenceModel ConfigureInvoicePreference(this AutoPersistenceModel autoPersistenceModel)
{
    return autoPersistenceModel.Override<InvoicePreference>(map =>
    {
        map.Table("SubgroupInvoicePreference");
        map.Schema(RetirementStatementsSchemaName);
    });
}

【问题讨论】:

  • 这是来自 NH profiler 的确切消息吗?
  • 这不是确切的信息。它具有类型的实际名称。警告:禁用 Neb.RetirementStatements.Services.Domain.Subgroup 的惰性属性获取,因为它不支持实体级别的惰性
  • 似乎与这个问题有关。 stackoverflow.com/questions/4888140/…

标签: c# .net nhibernate lazy-loading nhprof


【解决方案1】:

InvoicePreference 被称为 hasone。由于默认情况下它是惰性加载的,NHibernate 将创建一个代理来填充属性 InvoicePreference 并为此它需要来自 InvoicePreference 的标识,该标识在子组中不存在。因此它必须使用 propertyref 中的属性来查询它。

要解决这个问题.Not.LazyLoad() 和/或.Fetch.Join()

【讨论】:

  • 我知道如何进行预加载和获取策略的细微差别,但实际上我不想对那个属性/关联做任何事情。我根本没有尝试加载/访问它。如果是这样的话,那么是的,我想急切地加载它。
  • 我只是想知道为什么它专门尝试延迟加载这种关系。我没有访问该属性或任何其他属性,例如员工和管理员。为什么它对其他两个关系不做同样的事情?它还应该尝试延迟加载员工和管理员。是不是其他两个是集合而 InvoicePreference 不是?无论如何,他们不应该都以同样的方式行事吗?在我访问这些属性之前,NHibernate 不应该尝试加载它们。
  • 这是你解释的另一种说法吗? property-ref:延迟加载仅适用于对象 id。当通过目标实体中的不同列解析属性关联时,NH 会急切地获取它。并不是说这不可能,只是没有实现:Bug
  • 不可能延迟加载它,因为(如我所说)创建代理 NH 需要它目前没有的被引用实体的 identity .这不是错误,而是使用 property-ref 时的妥协。使用 select 子句并直接投影到您需要的属性中
  • 这是一种可以采用的方法,但此时我将反转关联。从 Subgroup 中删除 InvoicePreference,摆脱映射,并在 InvoicePreference 中引用 Subgroup。所以我会将 SubgroupId 从 Guid 重构为实际的 Subgroup 类型。在这一点上,这是我做的最简单和最有效的事情。不过感谢您的建议。
【解决方案2】:

我猜 NH 禁用延迟加载“在实体级别”是有某种原因的,我理解为没有创建代理。这可能有几个原因。你之前有没有收到另一个警告?我真的不明白为什么它禁用了“延迟属性”,这意味着某些属性是延迟加载的。这是在映射中明确使用的功能,但我在您的映射定义中看不到类似的内容。

要克服 N+1,您可以使用 Fetch.Join。我对此有不好的体验,因为查询变得非常大。在复杂模型中,您可能会达到一些数据库服务器限制(例如查询的最大列数)。最好使用批量大小,这会显着减少查询的数量。看看my answer 到“Nhinerbate lazy loading of reference entity”。

【讨论】:

  • 其实我根本不希望它做急切加载。我不希望加载实体,因为我没有将它用于请求。我什至没有碰那个属性。我当然在使用 AutoMapper,但据我所知,它也没有触及该属性,因为它没有在正在执行的映射中使用。
  • 如果您不想急切加载,请不要将其关闭。不要做 Fetch.Join 并使用批量大小。我不知道你为什么会收到这个警告。您可以在 NH 分析器论坛/支持网站上提问。
  • 会考虑的。谢谢斯特凡。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 2012-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多