问题
I want to do something like this...
return GetSession()
.ToPagedList<Employee>(page, pageSize,
x=> x.SetFetchMode(DomainModelHelper.GetAssociationEntityNameAsPlural<Team>(), FetchMode.Eager));
But I don't know how to pass this Func<ICriteria,ICriteria>
into the ISession
or ICriteria
.
I have a standard paging extension method and this extension method shall have an overload where I can pass additional ICriteria methods, so that I can additionally set up the FetchMode
or something else.
Extension Method:
public static class CriteriaExtensions
{
public static PagedList<T> ToPagedList<T>(this ISession session, int page, int pageSize) where T : Entity
{
var totalCount = TotalCount<T>(session);
return new PagedList<T>(session.CreateCriteria<T>()
.SetFirstResult(pageSize * (page - 1))
.SetMaxResults(pageSize * page)
.Future<T>().ToList(), page, pageSize, totalCount);
}
public static PagedList<T> ToPagedList<T>(this ISession session, int page, int pageSize, Func<ICriteria, ICriteria> action) where T : Entity
{
var totalCount = TotalCount<T>(session);
...
}
private static int TotalCount<T>(ISession session) where T : Entity
{
return session.CreateCriteria<T>()
.SetProjection(Projections.RowCount())
.FutureValue<Int32>().Value;
}
}
edit:
Without an overload it would look like this:
return GetSession()
.CreateCriteria<Employee>()
.SetFetchMode(DomainModelHelper.GetAssociationEntityNameAsPlural<Team>(), FetchMode.Eager)
.ToPagedList<Employee>(page, pageSize);
Extension Method:
public static class CriteriaExtensions
{
public static PagedList<T> ToPagedList<T>(this ICriteria criteria, int page, int pageSize) where T : Entity
{
var copiedCriteria = (ICriteria) criteria.Clone();
var totalCount = TotalCount(criteria);
return new PagedList<T>(copiedCriteria
.SetFirstResult(pageSize * (page - 1))
.SetMaxResults(pageSize * page)
.Future<T>().ToList(), page, pageSize, totalCount);
}
private static int TotalCount(ICriteria criteria)
{
return criteria
.SetProjection(Projections.RowCount())
.FutureValue<Int32>().Value;
}
}
The line var copiedCriteria = (ICriteria) criteria.Clone();
smells here, but I don't know how to change this.
Which approach would you suggest?
回答1:
From my understanding, you're trying to modify the behaviour of the criteria from outside the method that creates it.
Hence you have:
public IList<T> GetPageOf<T>(int page, int pageSize, Func<ICriteria,ICriteria> modifier)
{
return Session.CreateCriteria<T>()
.SetFirstResult(pageSize * (page-1))
.SetMaxResults(pageSize)
.ToList<T>();
}
All you need to do to give the modifier a chance is to change the body to:
return modifer(Session.CreateCriteria<T>) //the modifer gets first dibs on the criteria
.SetFirstResult(pageSize * (page-1))
.SetMaxResults(pageSize)
.ToList<T>();
Be aware, that changing the fetch-mode for many-to-many and many-to-one relationships in criteria that used SetFirstResult or SetMaxResults can result in the wrong number of rows being retrieved.
回答2:
A bit late, but hey!
The easiest thing to do is to extend IQueryOver instead of ICriteria, like so:
public static PaginatedList<T> Paginate<T>(this IQueryOver<T, T> instance, int page, int pageSize) where T : Entity {
var countCriteria = instance.ToRowCountQuery();
var totalCount = countCriteria.FutureValue<int>();
var items = instance.Take(pageSize).Skip((page- 1)*pageSize).List<T>();
return new PaginatedList<T>(items, page, pageSize, totalCount.Value);
}
This will allow you to do all your eager fetching (they will be removed in the row count query, but the criterias will remain the same). Example:
session.QueryOver<Customer>()
.Where(x => x.Status == CustomerStatus.Preferred)
.Fetch(x => x.Orders).Eager
.Paginate(1, 10);
Will yield two sql queries, like this:
For all items:
SELECT this_.id, this_.url, order_.sum FROM Customers this_ LEFT OUTER JOIN orders order_ ON this_.id = order_.customer_id WHERE this_.status = 1 LIMIT 10;
And for the count:
SELECT count(*) as y0_ FROM Customers this_ WHERE this_.type = 1;
来源:https://stackoverflow.com/questions/3569281/nhibernate-paging-with-icriteria-and-optional-icriteria-calls