nhibernate 기준에 투영을 추가하면 기본 엔티티 선택을 수행하는 것이 멈출 수 있습니다.
-
10-07-2019 - |
문제
데이터 지원 페이징을 선택하는 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;