2014-09-16 2 views
2

데이터베이스 액세스에 nHibernate를 사용하고 있습니다. 특정 날짜 이후에 모든 구성원 업무 일지 항목을 찾기 위해 각 구성원에 대해 설정된 PreviousId라는 복잡한 쿼리를 수행해야합니다. 나는 쉽게하기위한 SQL을 작성할 수 있습니다nHibernate QueryOver를 사용하여 하위 집합에 연결

SELECT J.MemberId, J.PreviousId 
FROM tblMemMemberStatusJournal J 
INNER JOIN (
    SELECT MemberId, 
     MIN(EffectiveDate) AS EffectiveDate 
    FROM tblMemMemberStatusJournal 
    WHERE EffectiveDate > @StartOfMonth 
     AND (PreviousId is NOT null) 
    GROUP BY MemberId 
) AS X ON (X.EffectiveDate = J.EffectiveDate AND X.MemberId = J.MemberId) 

내가 nHibernate 수는이 정보를 생성려고 많은 문제가 오전하지만. QueryOver 사용법에 대한 많은 문서가 없습니다.

나는 다른 곳에서 정보를보고 있었지만 그 중 어느 것도 매우 명확하지 않고 어떤 방식으로 일이 이루어지는 이유에 대한 실제적인 설명이 거의 없다. Selecting on Sub Queries in NHibernate with Critieria API에 대한 대답은 현재 수행중인 작업에 대한 적절한 예를 제공하지 않았으므로이를 복제 할 수 없었습니다.

나는이 만들어 쿼리의 내부를 입수했습니다

IList<object[]> result = session.QueryOver<MemberStatusJournal>() 
     .SelectList(list => list 
      .SelectGroup(a => a.Member.ID) 
      .SelectMin(a => a.EffectiveDate)) 
     .Where(j => (j.EffectiveDate > firstOfMonth) && (j.PreviousId != null)) 
     .List<object[]>(); 

어느, 프로파일에 따라, SQL하게 :

SELECT this_.MemberId   as y0_, 
    min(this_.EffectiveDate) as y1_ 
FROM tblMemMemberStatusJournal this_ 
WHERE (this_.EffectiveDate > '2014-08-01T00:00:00' /* @p0 */ 
    and not (this_.PreviousLocalId is null)) 
GROUP BY this_.MemberId 

를하지만 좋은를 찾는하고 있지 않다 이 하위 집합을 상위 쿼리와 실제로 결합하는 방법의 예. 누구든지 어떤 제안이 있습니까?

답변

1

실제로 하위 집합에 가입하지 않고 하위 집합을 필터링하고 있습니다. 이것을 알면 다른 수단,이 경우 상관 된 하위 쿼리를 통해 필터링 할 수 있습니다.

아래의 솔루션은 먼저 내부 하위 쿼리로 작동하도록 분리 된 쿼리를 만듭니다. 별칭을 사용하여 내부 쿼리의 속성과 외부 쿼리의 속성을 서로 연결할 수 있습니다.

MemberStatusJournal memberStatusJournalAlias = null; // This will represent the 
                // object of the outer query 

var subQuery = QueryOver.Of<MemberStatusJournal>() 
        .Select(Projections.GroupProperty(Projections.Property<MemberStatusJournal>(m => m.Member.ID))) 
        .Where(j => (j.EffectiveDate > firstOfMonth) && (j.PreviousId != null)) 
        .Where(Restrictions.EqProperty(
          Projections.Min<MemberStatusJournal>(j => j.EffectiveDate), 
          Projections.Property(() => memberStatusJournalAlias.EffectiveDate) 
         ) 
         ) 
        .Where(Restrictions.EqProperty(
          Projections.GroupProperty(Projections.Property<MemberStatusJournal>(m => m.Member.Id)), 
          Projections.Property(() => memberStatusJournalAlias.Member.Id) 
         )); 

var results = session.QueryOver<MemberStatusJournal>(() => memberStatusJournalAlias) 
        .WithSubquery 
        .WhereExists(subQuery) 
        .List(); 

는 다음과 같이 SQL 쿼리를 생성 할 것이다 : 이것은 당신이 질문을 연 inner join 쿼리보다 덜 효율적 보이는

SELECT blah 
FROM tblMemMemberStatusJournal J 
WHERE EXISTS (
    SELECT J2.MemberId 
    FROM tblMemberStatusJournal J2 
    WHERE J2.EffectiveDate > @StartOfMonth 
     AND (J2.PreviousId is NOT null) 
    GROUP BY J2.MemberId 
    HAVING MIN(J2.EffectiveDate) = J.EffectiveDate 
    AND J2.MemberId = J.MemberId 
) 

. 하지만 내 경험에 따르면 SQL 쿼리 최적화 도구는이를 내부 조인으로 변환 할만큼 충분히 똑똑합니다. 이것을 확인하려면 SQL Studio를 사용하여 두 쿼리의 실행 계획을 생성하고 비교할 수 있습니다.

관련 문제