问题
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