Хорошо, я опубликую это как ответ, потому что он делает в основном то, что хотел. Однако я хотел бы получить некоторую обратную связь, а также, возможно, ответ на мое одно предостережение о решении:
Я создал интерфейс под названием IPagedList.
public interface IPagedList<T> : IList<T>, ICollection
{
IList<T> GetPagedList(int pageNo, int pageSize);
}
Затем создал базовый класс, который он наследует от IPagedList:
public class PagedList<T> : IPagedList<T>
{
private List<T> _collection = new List<T>();
public IList<T> GetPagedList(int pageNo, int pageSize)
{
return _collection.Take(pageSize).Skip((pageNo - 1) * pageSize).ToList();
}
public int IndexOf(T item)
{
return _collection.IndexOf(item);
}
public void Insert(int index, T item)
{
_collection.Insert(index, item);
}
public void RemoveAt(int index)
{
_collection.RemoveAt(index);
}
public T this[int index]
{
get
{
return _collection[index];
}
set
{
_collection[index] = value;
}
}
public void Add(T item)
{
_collection.Add(item);
}
public void Clear()
{
_collection.Clear();
}
public bool Contains(T item)
{
return _collection.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_collection.CopyTo(array, arrayIndex);
}
int Count
{
get
{
return _collection.Count;
}
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return _collection.Remove(item);
}
public IEnumerator<T> GetEnumerator()
{
return _collection.GetEnumerator();
}
int ICollection<T>.Count
{
get { return _collection.Count; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return _collection.GetEnumerator();
}
public void CopyTo(Array array, int index)
{
T[] arr = new T[array.Length];
for (int i = 0; i < array.Length ; i++)
{
arr[i] = (T)array.GetValue(i);
}
_collection.CopyTo(arr, index);
}
int ICollection.Count
{
get { return _collection.Count; }
}
// The IsSynchronized Boolean property returns True if the
// collection is designed to be thread safe; otherwise, it returns False.
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return this;
}
}
}
Затем я создаю IUserCollectionType для NHibernate для использования в качестве настраиваемого типа коллекции и NHPagedList, который наследуется от PersistentGenericBag, а IPagedList - как самой фактической коллекции. Я создал два отдельных класса для них, потому что казалось, что использование IUserCollectionType никак не повлияло на фактическую коллекцию, которая будет использоваться, поэтому я оставил эти две части логики раздельными. Код ниже для обоих вышеперечисленных:
public class PagedListFactory<T> : IUserCollectionType
{
public PagedListFactory()
{ }
#region IUserCollectionType Members
public bool Contains(object collection, object entity)
{
return ((IList<T>)collection).Contains((T)entity);
}
public IEnumerable GetElements(object collection)
{
return (IEnumerable)collection;
}
public object IndexOf(object collection, object entity)
{
return ((IList<T>)collection).IndexOf((T)entity);
}
public object Instantiate(int anticipatedSize)
{
return new PagedList<T>();
}
public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
{
return new NHPagedList<T>(session);
}
public object ReplaceElements(object original, object target, ICollectionPersister persister,
object owner, IDictionary copyCache, ISessionImplementor session)
{
IList<T> result = (IList<T>)target;
result.Clear();
foreach (object item in ((IEnumerable)original))
{
result.Add((T)item);
}
return result;
}
public IPersistentCollection Wrap(ISessionImplementor session, object collection)
{
return new NHPagedList<T>(session, (IList<T>)collection);
}
#endregion
}
NHPagedList следующий:
public class NHPagedList<T> : PersistentGenericBag<T>, IPagedList<T>
{
public NHPagedList(ISessionImplementor session) : base(session)
{
_sessionImplementor = session;
}
public NHPagedList(ISessionImplementor session, IList<T> collection)
: base(session, collection)
{
_sessionImplementor = session;
}
private ICollectionPersister _collectionPersister = null;
public NHPagedList<T> CollectionPersister(ICollectionPersister collectionPersister)
{
_collectionPersister = collectionPersister;
return this;
}
protected ISessionImplementor _sessionImplementor = null;
public virtual IList<T> GetPagedList(int pageNo, int pageSize)
{
if (!this.WasInitialized)
{
IQuery pagedList = _sessionImplementor
.GetSession()
.CreateFilter(this, "")
.SetMaxResults(pageSize)
.SetFirstResult((pageNo - 1) * pageSize);
return pagedList.List<T>();
}
return this
.Skip((pageNo - 1) * pageSize)
.Take(pageSize)
.ToList<T>();
}
public new int Count
{
get
{
if (!this.WasInitialized)
{
return Convert.ToInt32(_sessionImplementor.GetSession().CreateFilter(this, "select count(*)").List()[0].ToString());
}
return base.Count;
}
}
}
Вы заметите, что он проверит, была ли коллекция инициализирована или нет, чтобы мы знали, когда проверять базу данных на предмет списка страниц, или когда просто использовать ток в объектах памяти.
Теперь все готово, просто измените текущие ссылки IList на своих моделях на IPagedList, а затем сопоставьте NHibernate с новой настраиваемой коллекцией, используя беглый NHibernate ниже, и вы готовы к работе.
.CollectionType<PagedListFactory<Recipient>>()
Это первое исправление этого кода, поэтому для его совершенствования потребуется некоторый рефакторинг и модификации.
Моя единственная проблема на данный момент состоит в том, что он не получит элементы с постраничным распределением в том порядке, который файл сопоставления предлагает для отношения родитель-потомок. Я добавил на карту атрибут order-by, и он просто не будет обращать на него внимания. Где, как и в любом другом месте, где предложения в каждом запросе не проблема. У кого-нибудь есть идеи, почему это может происходить и есть ли что-нибудь вокруг этого? Я буду разочарован, если не смогу обойтись без этого.