NHibernate - Пейджинг с ICriteria и дополнительные вызовы ICriteria - PullRequest
1 голос
/ 25 августа 2010

Я хочу сделать что-то вроде этого ...

return GetSession()
        .ToPagedList<Employee>(page, pageSize, 
        x=> x.SetFetchMode(DomainModelHelper.GetAssociationEntityNameAsPlural<Team>(), FetchMode.Eager));

Но я не знаю, как передать это Func<ICriteria,ICriteria> в ISession или ICriteria.

У меня есть стандартный метод расширения подкачки, и у этого метода расширения будет перегрузка, когда я могу передать дополнительные методы ICriteria, чтобы я мог дополнительно настроить FetchMode или что-то еще.

Метод расширения:

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;
    }
}

редактирование:

Без перегрузки это выглядело бы так:

return GetSession()
                .CreateCriteria<Employee>()
                .SetFetchMode(DomainModelHelper.GetAssociationEntityNameAsPlural<Team>(), FetchMode.Eager)
                .ToPagedList<Employee>(page, pageSize);

Метод расширения:

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;
    }
}

Линия var copiedCriteria = (ICriteria) criteria.Clone(); пахнет здесь, но я не знаю, как это изменить.

Какой подход вы бы предложили?

Ответы [ 2 ]

0 голосов
/ 03 января 2012

Немного поздно, но эй!

Самое простое, что можно сделать - это расширить IQueryOver вместо ICriteria, например так:

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);
}

Это позволит вам выполнить все ваши задачивыборка (они будут удалены в запросе количества строк, но критерии останутся прежними).Пример:

session.QueryOver<Customer>()
       .Where(x => x.Status == CustomerStatus.Preferred)
       .Fetch(x => x.Orders).Eager
       .Paginate(1, 10);

выдаст два sql запроса, например:

Для всех элементов:

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;

И для подсчета:

SELECT count(*) as y0_ FROM Customers this_ WHERE this_.type = 1;
0 голосов
/ 31 августа 2010

Насколько я понимаю, вы пытаетесь изменить поведение критериев вне метода, который его создает.

Следовательно, у вас есть:

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>();
}

Все, что вам нужно сделатьдать модификатору шанс изменить тело на:

return modifer(Session.CreateCriteria<T>) //the modifer gets first dibs on the criteria
           .SetFirstResult(pageSize * (page-1))
           .SetMaxResults(pageSize)
           .ToList<T>();

Имейте в виду, что изменение режима выборки для отношений «многие ко многим» и «многие к одному» в критериях, которые использовали SetFirstResult илиSetMaxResults может привести к неправильному количеству извлекаемых строк.

...