NHibernate可以在不延迟加载整个集合的情况下查询特定的孩子吗? [英] Can NHibernate query for specific children without lazy loading the entire collection?
问题描述
当我有一个带有一对多子集合的实体对象,并且我需要查询一个特定的子对象时,有没有我想不出的功能或一些聪明的模式来避免NHibernate获取整个子集合?
When I have an entity object with a one-to-many child collection, and I need to query for a specific child object, is there a feature or some clever pattern I haven't come up with yet to avoid that NHibernate fetches the entire child collection?
示例:
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
}
}
}
我知道这不是最好的例子,因为在这种情况下,可能只是直接查询Child实体,但是我遇到的情况是我已经有一个Parent对象,需要遍历它的特定子树.
I know it's not the best example because in this case one would probably just query the Child entities directly, but I have encountered situations where I already had a Parent object and needed to traverse specific sub-trees through it.
推荐答案
简短答案:否.更长的答案:您可以花些力气就能做到这一点.
Short answer: no. Longer answer: you can make it do this, with some sleight of hand.
Rippo上面的答案显示了如何以正确的NHibernate方式进行操作(无论是与Linq还是QueryOver或HQL无关紧要-关键是您必须走出父级->子级关系才能做到)询问).您可以更进一步,将其掩藏在立面的后面.但是要这样做,您必须完全删除映射关系,并始终用查询替换它.您将取出父"->子"映射,但保留子"->父"映射不变;然后在Parent上重新编写该属性,如下所示:
Rippo's answer above shows how you would do it the 'proper' NHibernate way (whether it's with Linq or QueryOver or HQL doesn't really matter - the point is you have to step outside the parent -> child relationship to do a query). You can take this a step further and disguise this behind a façade. But to do so, you have to remove the mapped relationship entirely and replace it with a query at all times. You'd take out the Parent -> Children mapping, but leave the Child -> Parent mapping intact; then re-write the property on Parent to look like this:
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
时,您将获得一个可查询的集合,因此您可以编写
Now, when you use Parent.Children
you get back a queryable collection, so you could then write
IEnumerable<Child> childrenNamedBob = parent.Children.Where(c => c.Name == "Bob");
您可以执行此操作并保留映射的唯一方法是修改NHibernate的集合对象(或注入您自己的对象). Diego Mijelshon(围绕这些部分)写了一个尖峰,为NHibernate集合添加了IQueryable支持,因此您可以做到
The only way you could do this and preserve the mapping is to amend NHibernate's collection objects (or inject your own). Diego Mijelshon (who is around these parts) wrote a spike of exactly that, adding IQueryable support to NHibernate collections so you could do
IEnumerable<Child> childrenNamedBob = parent.Children.AsQueryable().Where(c => c.Name == "Bob");
但是据我所见,这再也没有进行过了,也没有明显的计划将此功能添加到NH中.我已经运行了Diego的代码,并且确实可以运行,但是显然它不是生产质量,也没有经过测试,而且我认为它甚至没有作为私有补丁正式发布过.
But from what I can see, this never went any further and there's no apparent plan to add this capability to NH. I have run Diego's code and it does work, but obviously it's not production quality and hasn't been tested, and I don't think it's ever been officially 'released' even as a private patch.
以下是NH问题跟踪器上的讨论链接: https://nhibernate.jira. com/browse/NH-2319
Here's the link to the discussion on the NH issue tracker: https://nhibernate.jira.com/browse/NH-2319
我相信NH应该开箱即用地支持这一点,因为对于大多数.NET开发人员来说,这是自然的方式,它想与几乎所有可枚举的东西进行交互,因为我们有了Linq,并且没有侧边就无法做到-将无限集合加载到RAM的效果很糟糕.但是传统的NH模式是会话->查询,这就是99%的人使用的方式.
I believe NH should support this out of the box, as it's a natural way for most .NET devs to want to interact with pretty much anything enumerable, now that we have Linq, and not being able to do it without the side-effect of loading an unbounded collection into RAM sucks. But the traditional NH model is session -> query and that's what 99% of people use.
这篇关于NHibernate可以在不延迟加载整个集合的情况下查询特定的孩子吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!