3

내가 NHibernate에에 FluentNHibernate와 Linq에와 NHibernate에 3.2을 사용하고 있습니다. 나는 Linq를 NHibernate에 사용하여 자식을로드하지 않고 컬렉션의 모든 손자를 열심히로드하려고한다. 예를 들어, 나는 다음과 같은 클래스가 있다고 가정 :Linq에 - 열망로드 손자하지만 아이들

각 부모
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 객체를로드해야합니다. 자식은 ProhibitivelyLargeType 유형의 필드를 포함하는데, 이것은 느린 로딩이 아니기 때문에 Child에 대해서는 아무것도로드하지 않는 것을 선호합니다. 그러나 FetchMany/ThenFetchMany를 사용하지 않으면 N + 1 문제가 발생하며 각 하위 및 하위 노드에 대한 데이터베이스로의 이동이 필요합니다. 이는 또한 용납 될 수 없습니다.

또한, 나는 ProhibitivelyLargeField LazyLoad을 만들 수 있습니다. 그러나 Child 클래스를 사용하는 대부분의 응용 프로그램은 ProhibitivelyLargeField를 사용해야하지만 이미 LazyLoad 인 RarelyUsedLargeField를로드하지 않으려합니다. 내가 이해할 수있는 한 가지 LazyLoad 속성을로드하면 모두로드되므로이 솔루션을 사용하면 일반적인 사용 사례가 줄어들 수 있습니다.

내가 NHibernate에 Linq에를 사용하여 찾고 있어요 방금 정보를 얻을 수있는 방법이 있나요, 아니면이 기준 쿼리 API를 사용해야합니까?

감사합니다.

편집

는 ProhibitivelyLargeField LazyLoad는 다음 QueryOver입니다

+0

는'ProhibitivelyLargeType'을 정의한다? – Firo

+0

@Firo 아니요, 금지 된 대용량 필드에는 레이저로드 할 수 없습니다. – chris4600

+0

왜냐하면 ...? 나는 게으른로드를 비활성화하는 유효한 예제를 아직 보지 못했습니다. –

답변

0

바람직하지 않을 수도 있습니다 만드는 이유의 예를 제공합니다. 결과를 두 개의 작은 단계로로드한다는 아이디어 만 보여줍니다. 어쩌면 당신은 내가 NHibernate에 사용하지 않은,하지만 난 엔티티에 LINQ를 사용하고, 내가 무엇을보고에서 당신은 데이터베이스 쿼리의 톤을하고있는 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(); 
+0

감사합니다. 당신이 제공 한 코드는 내가 지금하고있는 것과 비슷합니다. "LINQ로 변환"부분은 내가 빠져 나갈 수없는 부분입니다. – chris4600

-1

로 번역 할 수 있습니다. 대신 원하는 데이터 만 반환하는 단일 행 쿼리를 수행해야합니다.

from parent in session.Parents 
let children = parent.Children 
select new {parent = parent, children.SelectMany(c => c.Grandchildren).Sum(gc => gc.Age)} 

잘못된 정보가 있으면 알려주세요. C#을 한동안 사용하지 않았고 전화를 사용하고 있습니다. 이 방법은 사람을 작동하지 않으면

그냥 말해 나는 그것을 삭제됩니다. 옵션을 lazyloaded으로

+0

감사합니다.하지만 Linq가 NHibernate를 올바르게 이해하고 있다면, 제공 한 것과 같은 직접 구현은 각 하위 데이터베이스와 각 하위 데이터베이스에 대해 한 번만 수행하게됩니다. (FetchMany/ThenFetchMany 부분은 한 번에 모든 것을 가져 오도록 강제하는 것입니다.) – chris4600

+0

그건 이상 할 것입니다. 테스트 해 보셨습니까? – tster