nhibernate 기준에 투영을 추가하면 기본 엔티티 선택을 수행하는 것이 멈출 수 있습니다.

StackOverflow https://stackoverflow.com/questions/1644776

문제

데이터 지원 페이징을 선택하는 nhibernate 기준을 작성하고 있습니다. 나는 사용하고있다 COUNT(*) OVER() SQL Server 2005 (+)의 표현식은 제안 Ayende Rahien에 의해. 총 얼마나 많은 페이지가 있는지 계산할 수 있으려면 해당 숫자가 필요합니다. 이 솔루션의 아름다움은 행 카운트를 유지하기 위해 두 번째 쿼리를 실행할 필요가 없다는 것입니다.

그러나 작업 기준을 작성할 수없는 것 같습니다 (Ayende는 HQL 쿼리 만 제공합니다).

여기에 내가 원하는 것을 보여주는 SQL 쿼리가 있습니다. 문제에 초점을 맞추기 위해 실제 페이징 논리를 의도적으로 제외 시켰습니다.

SELECT Items.*, COUNT(*) OVER() AS rowcount
FROM Items

HQL은 다음과 같습니다.

select
    item, rowcount()
from 
    Item item

주목하십시오 rowcount() 기능은 사용자 정의 nhibernate 방언에 등록되어 다음으로 해결됩니다. COUNT(*) OVER() SQL에서.

요구 사항은 쿼리가 기준을 사용하여 표현되어야합니다. 불행히도, 나는 그것을 올바르게 얻는 방법을 모른다 :

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(
       Projections.SqlFunction("rowcount", NHibernateUtil.Int32));

투영을 추가 할 때마다 NHibernate는 선택하지 않습니다 item (투영이없는 것처럼) rowcount() 나는 정말로 둘 다 필요합니다. 또한 프로젝트 할 수없는 것 같습니다 item 전체적으로, 그것은 단지 속성 일 뿐이며 나는 그들 모두를 나열하고 싶지 않습니다.

누군가가 이것에 대한 해결책이 있기를 바랍니다. 어쨌든 감사합니다.

도움이 되었습니까?

해결책

기준에서는 불가능하다고 생각합니다. 한계가 있습니다.

후속 쿼리에서 ID와로드 항목을 가져올 수 있습니다.

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(Projections.ProjectionList()
       .Add(Projections.SqlFunction("rowcount", NHibernateUtil.Int32))
       .Add(Projections.Id()));

마음에 들지 않으면 HQL을 사용하면 최대 결과 수를 설정할 수 있습니다.

IList<Item> result = Session
    .CreateQuery("select item, rowcount() from item where ..." )
    .SetMaxResult(100)
    .List<Item>();

다른 팁

CreateMulticriteria를 사용하십시오.

DB에 한 번의 적중만으로 2 개의 간단한 진술을 실행할 수 있습니다.

기준을 사용하는 것이 왜 요구 사항인지 궁금합니다. session.createsqlquery를 사용할 수 없습니까? 한 쿼리로 실제로해야한다면 항목 객체와 카운트를 다음과 같이 철회 할 것을 제안했을 것입니다.

select {item.*}, count(*) over() 
from Item {item}

... 이렇게하면 카운트와 함께 쿼리에서 항목 객체를 되 찾을 수 있습니다. Hibernate의 캐싱에 문제가있는 경우 기본 쿼리와 관련된 쿼리 공간 (엔티티/테이블 캐시)을 구성하여 오래된 쿼리 캐시 항목이 자동으로 지워집니다.

귀하의 질문을 제대로 이해하면 해결책이 있습니다. 나는이 같은 문제로 꽤 어려움을 겪었다.

우리가 같은 페이지에 있는지 확인하기 위해 내가 가진 문제를 신속하게 설명하겠습니다. 내 문제는 페이징으로 나왔습니다. UI에 10 개의 레코드를 표시하고 싶지만 또한 알고 싶습니다. 필터 기준과 일치하는 레코드 수. NH Criteria API를 사용 하여이 작업을 수행하고 싶었지만 Row Count에 대한 투영을 추가 할 때 쿼리가 더 이상 작동하지 않으며 결과는 얻지 못할 것입니다 (특정 오류는 기억하지 못하지만 귀하의 것 같습니다. '다시 얻음).

다음은 내 솔루션입니다 (현재 생산 코드에서 복사 및 붙여 넣기). "SessionError"는 ISDEV, ISREAD 및 ISRESOLVED의 3 필터 기준에 따라 PAGED 데이터를 검색하는 비즈니스 엔티티의 이름입니다.

ICriteria crit = CurrentSession.CreateCriteria(typeof (SessionError))
    .Add(Restrictions.Eq("WebApp", this));

if (isDev.HasValue)
    crit.Add(Restrictions.Eq("IsDev", isDev.Value));

if (isRead.HasValue)
    crit.Add(Restrictions.Eq("IsRead", isRead.Value));

if (isResolved.HasValue)
    crit.Add(Restrictions.Eq("IsResolved", isResolved.Value));

// Order by most recent
crit.AddOrder(Order.Desc("DateCreated"));

// Copy the ICriteria query to get a row count as well
ICriteria critCount = CriteriaTransformer.Clone(crit)
    .SetProjection(Projections.RowCountInt64());
critCount.Orders.Clear();

// NOW add the paging vars to the original query
crit = crit
    .SetMaxResults(pageSize)
    .SetFirstResult(pageNum_oneBased * pageSize);

// Set up a multi criteria to get your data in a single trip to the database
IMultiCriteria multCrit = CurrentSession.CreateMultiCriteria()
    .Add(crit)
    .Add(critCount);

// Get the results
IList results = multCrit.List();

List<SessionError> sessionErrors = new List<SessionError>();
foreach (SessionError sessErr in ((IList)results[0]))
    sessionErrors.Add(sessErr);

numResults = (long)((IList)results[1])[0];

그래서 선택적인 제한 사항으로 기본 기준을 만듭니다. 그런 다음 복제하고 복제 된 기준에 행 카운트 투영을 추가합니다. 내가 복제한다는 점에 유의하십시오 ~ 전에 페이징 제한을 추가합니다. 그런 다음 원본 및 클로닝 된 Icriteria 객체를 포함하도록 Imulticriteria를 설정하고 Imulticriteria를 사용하여 두 가지를 실행합니다. 이제 원래 iCRiteria의 PAGED 데이터를 가지고 있으며 (와이어를 통해 필요한 데이터 만 드래그했습니다), 실제 레코드가 내 기준 (표시 또는 페이징 링크를 작성하는 데 유용한 실제 레코드 수)의 원시 수가 있습니다. 이 전략은 저에게 잘 작동했습니다. 이것이 도움이되기를 바랍니다.

세션에서 SetResultTransformer ()를 호출하여 사용자 정의 결과 변압기를 조사하는 것이 좋습니다.

클래스 매핑에서 공식 속성을 만듭니다.

<property name="TotalRecords" formula="count(*) over()" type="Int32" not-null="true"/>;

IList<...> result = criteria.SetFirstResult(skip).SetMaxResults(take).List<...>();
totalRecords = (result != null && result.Count > 0) ? result[0].TotalRecords : 0;
return result;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top