NHibernate的可以查询特定的儿童无延迟加载整个集合?(Can NHibernate quer

2019-08-06 22:15发布

当我有一个一对多的子集合一个实体对象,我需要查询特定的子对象,是有一个功能或一些聪明的模式我还没有想出尚未避免NHibernate的取整子集?

例:

class Parent 
{
    public virtual int Id { get; proteced set; } // generated PK
    public virtual IEnumerable<Child> Children { get; proteced set; }
}

class Child
{
    public virtual int Id { get; protected set; } // generated PK
    public virtual string Name { get; protected set; }
    public virtual Parent Parent { get; protected set; }
}

// mapped with Fluent

class Service
{

    private readonly ISessionFactory sessionFactory;

    public Service(ISessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

    void DoSomethingWithChildrenNamedBob(int parentId)
    {
        using(var session = sessionFactory.OpenSession())
        {
            var parent = session.Get<Parent>(parentId);
            // Will cause lazy fetch of all children!
            var childrenNamedBob = parent.Children.Where(c => c.Name == "Bob"); 
            // do something with the children
        }
    }
}

我知道这是不是最好的例子,因为在这种情况下,人们可能只是直接查询儿童的实体,但我也遇到过,我已经有了一个父对象,并通过它来遍历特定子树需要的情况。

Answer 1:

简短的回答:没有。 较长的答案:你可以把它做到这一点,与手的一些花招。

上述Rippo的回答表明,你会怎么做了“适当的” NHibernate的方式(无论是使用LINQ或QueryOver或HQL其实并不重要 - 关键是你要踩父外 - >亲子关系做一个查询)。 您可以更进一步借此和掩盖这个幌子。 但要做到这一点,你必须完全移除映射关系,并在任何时候的查询替换它。 你会拿出父 - >儿童的映射,但留下孩子 - >父映射完好; 然后重新写上父母的财产,以这个样子:

public virtual IQueryable<Child> Children
{
    get
    {
        // somehow get a reference to the ISession (I use ambient context), then
        return session.Query<Child>().Where(c => c.Parent == this);
    }
}

现在,当您使用Parent.Children你回来可查询的集合,所以你可以接着写

IEnumerable<Child> childrenNamedBob = parent.Children.Where(c => c.Name == "Bob");

你能做到这一点,并保留映射的唯一方法是修改NHibernate的集合对象(或注入自己)。 迭戈Mijelshon(谁是围绕这些部件)写的正是这样一个尖峰,增加IQueryable的支持NHibernate的集合,所以你可以做

IEnumerable<Child> childrenNamedBob = parent.Children.AsQueryable().Where(c => c.Name == "Bob");

但是,从我所看到的,这个再没有什么长进,而且也没有明显的计划,这个功能添加到NH。 我已经运行迭戈的代码和它的工作,但显然它不是生产质量并没有经过测试,我不认为这是以往任何时候都正式“发布”甚至作为一个私人的补丁。

这里的链接到讨论的NH问题跟踪: https://nhibernate.jira.com/browse/NH-2319

我相信NH应该支持这个开箱即用,因为它是大多数.NET开发者想与几乎任何枚举交互的自然方式,现在我们有LINQ的,并且无副作用不能够做到这一点加载无限收集到RAM很烂。 但传统的NH模型会议 - >查询,这就是99%的人使用。



Answer 2:

我问上NHusers同样的问题在几个星期前,所以我怀疑,答案是没有得到答案you will always get all the parents children and then perform a in-memory filter 。 在许多情况下,这可能是在看到它的正确方法。

在你的情况我会重写查询是: -

var childrenNamedBob = session.Query<Children>()
  .Where(w => w.Parent.Id == parentId && w.Name == "Bob");

然后,只需获得母公司(如果childrenNamedBob有结果),你可以拨打电话: -

   var parent = childrenNamedBob.First().Parent;

或者你正确地指出: -

var parent = session.Get<Parent>(parentId);


Answer 3:

现在你可以做到这一点与NHibernate 5的情况下直接特定的代码!

见https://github.com/nhibernate/nhibernate-core/blob/master/releasenotes.txt

Build 5.0.0
=============================

** Highlights
...
    * Entities collections can be queried with .AsQueryable() Linq extension without being fully loaded.
...


文章来源: Can NHibernate query for specific children without lazy loading the entire collection?