【问题标题】:When does NHibernate JoinQueryOver load full collection?NHibernate JoinQueryOver 何时加载完整集合?
【发布时间】:2013-11-14 01:03:16
【问题描述】:

我有一个模型,其中 Person 具有 Registrations 的延迟加载集合。我的 NHibernate 3.3.3 查询在该关系中使用 JoinQueryOver 以及更多:

var reg = Session.QueryOver<Person>()
    .Where(p => p.ID == pid)
    .JoinQueryOver<Registration>(p => p.Registrations)
    .Where(r => r.IsDropped == false)
    .JoinQueryOver<Slot>(r => r.Slot)
    .JoinQueryOver<Position>(s => s.Position)
    .JoinQueryOver<AcademicTerm>(p => p.Term)
    .Where(t => t.ID == currentTerm.ID)
    .SingleOrDefault();

在日志中,我看到了预期的查询 SQL,并且得到了预期的 Person 实例,但是当我访问 Registrations 集合时,会(延迟)加载完整的注册集合。我原以为它只是符合条件的注册的部分集合。

a previous question 中,我遇到了相反的问题,并通过在查询中添加Fetch() 子句来解决它。

JoinQueryOver 条件何时会导致根实体具有部分集合,以及何时会具有将延迟加载的未加载集合?我觉得我应该明白这一点。

我对@9​​87654328@的流畅映射:

public class PersonMapping : ClassMap<Person>
{
    public PersonMapping()
    {
        Id(x => x.ID).GeneratedBy.Guid();
        Map(x => x.Username).Length(20).Unique();
        Map(x => x.HashedPassword).Length(Security.HashedPasswordEncodedLength);
        Map(x => x.PasswordSalt).Length(Security.PasswordSaltEncodedLength);
        Map(x => x.LastName).Length(25).Index("FullName");
        Map(x => x.FirstName).Length(20).Index("FullName");
        Map(x => x.StudentID).Length(12).Nullable();
        Map(x => x.EmployeeID).Length(12).Nullable();
        Map(x => x.EmailAddress).Length(72);
        Map(x => x.IsAdmin).Nullable();
        Map(x => x.IsAgencyStaff).Nullable();
        Map(x => x.IsCenterStaff).Nullable();
        Map(x => x.IsFaculty).Nullable();
        Map(x => x.IsRegistrant).Nullable();
        Map(x => x.IsStudent).Nullable();

        Map(x => x.Type);
        Map(x => x.AuthenticationMode);

        HasMany<Registration>(x => x.Registrations).KeyColumn("Registrant_id")
            .LazyLoad()
            .AsBag()
            .Inverse()
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.SaveUpdate();
    }
}

更新 将此与我的另一个问题(上面链接)进行比较,我遇到了相反的问题,即使用Left.JoinQueryOver 从基本实体获取集合。我在这里尝试过,然后得到了预期的部分集合。 (在另一种情况下,我实际上不需要左连接;我不记得它为什么在那里。)

无论有没有左连接,获取的记录都是相同的,但是 NHibernate 在一种情况下填充集合,而不是在另一种情况下。我怀疑这是我可以依赖的行为,所以我改变了我的策略,分别查询注册。

【问题讨论】:

    标签: nhibernate fluent-nhibernate queryover


    【解决方案1】:

    QueryOver中的这个条件:

    ...
    .JoinQueryOver<Registration>(p => p.Registrations)
    .Where(r => r.IsDropped == false)
    ...
    

    实际上是 Person 的 WHERE 子句。我的意思是,这个条件决定是否存在这样的Person,至少有一个Registration被丢弃。这不是一种方法,如何过滤注册集合。但是:

    NHibernate 有两种很好的方法来过滤集合本身。这些是 where 子句和 filter

    1。 where 子句

    简单地说:我们可以扩展集合映射,使用一条 SQL 语句,该语句将始终作为 where 条件添加。查看6.2. Mapping a Collection在哪里,提取:

    where="arbitrary sql where condition" ==(可选)指定检索或删除集合时要使用的任意 SQL WHERE 条件(如果集合应该 仅包含可用数据的子集)

    所以在我们的例子中是映射:

    HasMany<Registration>(
      ...
      .Where("IsDropped = 0"); // SQL Statement
    

    2。过滤设置

    虽然 where 子句是静态的,但嵌入到程序集/映射中...过滤器是一种动态执行此操作的方法。所以想象一下,我们有时希望有一组Registrations,下一次被删除,它们没有被删除。

    我们希望能够将"IsDropped = 0" 更改为"IsDropped = 1" (更好的方案是通过文化或语言切换)。这就是可以应用过滤器的地方,请参阅18.1. NHibernate filters

    有一个带有fluent的过滤器的小草稿,请参阅下面的链接以获得完整的图片。

    HasMany
      ...
      .ApplyFilter<MyFilter>()
    

    过滤器可能是这样的:

    public class MyFilter: FilterDefinition
    {
        public MyFilter()
        {
            WithName("dropped")
              .WithCondition("IsDropped == :isDropped")
              .AddParameter("isDropped", NHibernate.NHibernateUtil.Boolean);
        }
    }
    

    最后,我们可以为整个会话启用过滤器(酷,所有集合将在该事务/会话中以相同的方式过滤,所有集合都映射为MyFilter

    session.EnableFilter("dropped").SetParameter("isDropped", false);
    

    在这里查看更多:

    【讨论】:

    • 感谢您的全面回复。但是,我看不出这与我之前的问题(上面的链接)有何关系。在那里,我只检索了我想要完整的部分集合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多