2009-06-02 4 views
24

루트 엔티티를로드하고 모든 자식 콜렉션 및 집계 멤버를 열심히로드하려고합니다.NHibernate로 열망하는 자식 컬렉션

FluentNHibernate에서 SetFetchMode을 사용하려고했지만 3 레벨의 깊이가 있으므로 하위 컬렉션 중 하나에서 복제가 발생합니다. DistinctRootEntityResultTransformer은 불행히도 루트 중복 만 제거합니다.

return Session.CreateInvoiceBaseCriteria(query, archived) 
    .AddOrder(new Order(query.Order, query.OrderType == OrderType.ASC)) 
    .SetFetchMode("States", FetchMode.Eager) 
    .SetFetchMode("Attestations", FetchMode.Eager) 
    .SetFetchMode("AttestationRequests", FetchMode.Eager) 
    .SetFetchMode("AttestationRequests.Reminders", FetchMode.Eager) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()) 
    .List<Invoice>(); 

다중 쿼리 또는 이와 유사한 것을 사용할 수 있습니까?

또한이 접근 방식으로 인해 데이터베이스의 결과 집합이 불필요하게 커지지는 않습니까?

제안 사항?

답변

0

그것은 당신이, 내가이 글을보고하는 것이 좋습니다 것입니다 찾고있는 정확하게되지 않을 수도 있지만 :

Eager loading aggregate with many child collections

해당 사이트의 나머지 주위를 보면 당신은 논의 더욱 게시물을 찾을 수 있습니다 열망하는로드 및 기타 훌륭한 nHibernate 물건.

+2

실제로 좋은 기사이지만 내 상황에 적용 할 수 있는지 확실하지 않습니다. 특정 루트 엔티티를 로딩하는 것에 대한 기사에서 설명한 솔루션은 내 루트 엔티티 컬렉션을 열망하고 싶다. MultiCritera를 사용하려면 특정 엔티티를 지정하지 않고 모든 다른 쿼리를 연결하는 방법을 찾아야합니다. 그 방법을 제안 할 수 있습니까? – Kristoffer

+0

그 예제는 단 하나의 추가 계층 구조 레벨을 가지고 있지만, 손주없는 MultiQuery/MultiCriteria는 이후 쿼리가 이전 쿼리 (예 : 쿼리 # 1)의 결과를 참조 할 수 없으므로 쓸데없는 것 같습니다. select rootObjects r left join fetch children c where ... ... 쿼리 # 2 : c)에서 parent가있는 grandchildren g을 선택합니다. –

8

해결책을 찾았지만 꽤 좋지 않습니다. 먼저 Invoice ID를 모두 찾은 다음 다중 쿼리에서 사용하고 마지막에는 HashedSet을 통해 결과를 필터링합니다. 많은 수의 항목 때문에 때로는 정상적인 Restriction.In을 사용할 수 없으며 문자열로 보내야했습니다.

제안 된 비틀기는 무엇입니까?

var criteria = Session.CreateInvoiceBaseCriteria(query, archived) 
    .SetProjection(Projections.Id()); 

var invoiceIds = criteria.List<int>(); 
if (invoiceIds.Count > 0) 
{ 
    var joinedIds = JoinIDs(criteria.List<int>()); // To many ids to send them as parameters. 

    var sql1 = string.Format("from Invoice i inner join fetch i.States where i.InvoiceID in ({0}) order by i.{1} {2}", joinedIds, query.Order, query.OrderType.ToString()); 
    var sql2 = string.Format("from Invoice i inner join fetch i.AttestationRequests where i.InvoiceID in ({0})", joinedIds); 
    var sql3 = string.Format("from Invoice i inner join fetch i.Attestations where i.InvoiceID in ({0})", joinedIds); 

    var invoiceQuery = Session.CreateMultiQuery() 
     .Add(sql1) 
     .Add(sql2) 
     .Add(sql3); 

    var result = invoiceQuery.List()[0]; 

    return new UniqueFilter<Invoice>((ICollection)result); 
} 

return new List<Invoice>(); 
+0

이상한 경우 증명은 단일 쿼리로 가져옵니다. – Kristoffer

+0

+1, 실제로는 (그리고 불행히도) 이것을 달성하는 가장 좋은 방법 (성능면에서)입니다. –

+0

나는 비슷한 상황에있다. (한 번에 3 개의 레벨을 끌어 ​​당기려고한다.) 귀하의 솔루션은 중복을 제거하지만, 단지 2 레벨만큼 깊은 것으로 보입니다. 원래 질문에 대답에 포함되지 않은 "AttestationRequests.Reminders"라는 세 번째 레벨이 포함되었습니다. – MylesRip

2

답변을 얻으려면 : 예, 큰 결과가 나옵니다.

나는에 제안 : 그냥 순진 열망 특정 장소에

  • 를 가져 오는없이 쿼리를 작성

    • , 열심이 가져 오는 듯했지만 쿼리
    • 당 하나의 당신이 정말로 성능 문제를 얻는 경우에하는 당신을 인덱스로 해결할 수 없거나 쿼리 및 매핑 전략을 향상시켜 여러 가지 쿼리로 솔루션을 사용하십시오.
  • 관련 문제