我将NHibernate 3.2与FluentHibernate和Linq一起用于NHibernat。我想使用Linq到NHibernate来急切地加载集合的所有孙辈,而不必加载孩子。例如,假设我有以下类:
public class Parent
{
public virtual int Id { get; set; }
public virtual IList<Child> Children { get; set; }
}
public class ParentMap : ClassMap<Parent>
{
Id(x => x.Id);
HasManyToMany(x => x.Children).ExtraLazyLoad();
}
public class Child
{
public virtual int Id { get; set; }
public virtual IList<Parent> Parents { get; set; }
public virtual IList<Grandchild> Grandchildren { get; set; }
public virtual ProhibitivelyLargeType ProhibitivelyLargeField { get; set; }
public virtual ProhibitivelyLargeType RarelyUsedLargeField { get; set; }
}
public class ChildMap : ClassMap<Child>
{
Id(x => x.Id);
HasManyToMany(x => x.Parents).ExtraLazyLoad();
HasManyToMany(x => x.Grandchildren).ExtraLazyLoad();
Map(x => x.ProhibitivelyLargeField);
Map(x => x.RarelyUsedField).LazyLoad();
}
public class Grandchild
{
public virtual int Id { get; set; }
public virtual IList<Child> Children { get; set; }
public virtual int Age { get; set; }
}
public class GrandchildMap : ClassMap<Grandchild>
{
Id(x => x.Id);
HasManyToMany(x => x.Children).ExtraLazyLoad();
Map(x => x.Age);
}
对于每一位父母,我想知道他们所有孙辈的总年龄。我可以使用以下方法:
Dictionary<Parent, int> grandchildAges = session.Query<Parent>()
.FetchMany(p => p.Children)
.ThenFetchMany(c => c.Grandchildren)
.AsEnumerable()
.ToDictionary(
p => p,
p => p.Children.SelectMany(c => c.Grandchildren).Sum(g => g.Age)
);
这种方法产生正确的结果。但是,它需要加载所有的Child对象。Child包含一个类型为ProhibitivelyLargeType的字段,它不是惰性加载的,所以我真的不想加载任何关于Child的信息,而是它的ID。然而,如果我不使用FetchMany/ThenFetchMany,那么我就有N+1问题,它需要为每个Child和Grandchild访问数据库,这也是不可接受的。
或者,我可以制作ProhibitivelyLargeField LazyLoad。但是,大多数使用Child类的应用程序都需要使用ProhibitivelyLargeField,但它们不希望必须加载已经是LazyLoad的RarelyUsedLargeField。据我所知,加载一个LazyLoad属性会导致所有这些属性都被加载,所以这个解决方案会阻碍正常的用例。
有没有一种方法可以获得我正在使用Linq到NHibernate查找的信息,或者我必须使用Criteria Query API?
谢谢!
经过编辑,提供了一个示例,说明为什么禁用LargeField LazyLoad可能不受欢迎
下面是QueryOver。这只是为了表明在两个较小的步骤中加载结果的想法。也许你可以把它翻译成LINQ
// inititialize the dictionary
Grandchild grandchild = null;
Dictionary<Parent, int> dict = session.QueryOver<Parent>()
.JoinQueryOver(p => p.Childs)
.JoinAlias(c => c.GrandChilds, () => grandchild)
.Select(Projections.Group<Parent>(p => p.Id), Projections.Sum(() => grandchild.Age))
.AsEnumerable()
.Cast<object[]>()
.ToDictionary(
array => session.Load<Parent>(array[0]),
array => (int)array[1]
);
// initialize all Parent proxies
session.QueryOver<Patient>()
.WhereProperty(p => p.Id).In(dict.Keys.Select(p => p.Id))
.ToList();
我没有使用nhibernate,但我对实体使用了linq,据我所见,您正在进行大量的数据库查询。你应该做一个单行查询,只返回你想要的数据:
from parent in session.Parents
let children = parent.Children
select new {parent = parent, children.SelectMany(c => c.Grandchildren).Sum(gc => gc.Age)}
如果我做错了什么,我道歉。我已经有一段时间没有做C#了,我正在打电话。
如果这种方法不起作用,有人告诉我,我会删除它。