使用NHibernate在我的模型上实现IPagedList <T>

Joh*_*hn_ 6 c# asp.net nhibernate interface asp.net-3.5

我发现在使用NHibernate并在一个对象上创建一对多的关系时,当许多变得非常大时,它会显着减慢.现在我在我的存储库中有方法来收集该类型的分页IList,但是我更喜欢在模型上使用这些方法,因为这通常是其他开发人员首先要收集子对象列表的地方.

例如

RecipientList.Recipients将返回列表中的每个收件人.

我想实现一种方法,在我的模型中使用优选的接口添加对我的所有关系的分页,但实际上任何不会强制键入模型的关系.例如,拥有以下界面会很不错:

public interface IPagedList<T> : IList<T>
{
    int Count { get; }
    IList<T> GetPagedList(int pageNo, int pageSize);
    IList<T> GetAll();
}
Run Code Online (Sandbox Code Playgroud)

然后能够在代码中使用它...

IList<Recipient> recipients = RecipientList.Recipients.GetPagedList(1, 400);
Run Code Online (Sandbox Code Playgroud)

我一直试图想办法做到这一点,而不给模型任何分页意识,但我现在正撞在一堵砖墙上.

无论如何我可以用NHibernate为IList和lazyloading做的类似方式实现接口吗?我对NHibernate知之甚少知之甚少.

实现这个甚至是个好主意吗?您的想法将被认为是内部唯一的.NET开发人员,我没有人可以反复提出想法.

UPDATE

下面的帖子向我指出了NHibernate的自定义集合属性,它可以很好地工作.但是我不确定最好的解决方法是什么,我试图从PersistentGenericBag继承,以便它具有与IList相同的基本功能而没有太多工作,但是我不确定如何基于ISessionImplementor收集对象列表.我需要知道如何:

  • 获取我要填充的当前IList的某种ICriteria详细信息
  • 获取与IList关联的特定属性的映射详细信息,以便创建自己的ICriteria.

但是我不确定我是否可以做以上任何一种情况?

谢谢

Joh*_*hn_ 2

好吧,我将把这个作为答案发布,因为它主要做了我想做的事情。不过,我想要一些反馈,也可能需要对迄今为止解决方案的一个警告的答案:

我创建了一个名为 IPgedList 的接口。

public interface IPagedList<T> : IList<T>, ICollection
{

    IList<T> GetPagedList(int pageNo, int pageSize);

}
Run Code Online (Sandbox Code Playgroud)

然后创建一个继承自 IPgedList 的基类:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我为 NHibernate 创建一个 IUserCollectionType 用作自定义集合类型,并为 NHPgedList 创建一个继承自 PersistentGenericBag 的 IUserCollectionType,IPatedList 作为实际集合本身。我为它们创建了两个单独的类,因为 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
}
Run Code Online (Sandbox Code Playgroud)

NHPedList 接下来:

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

}
Run Code Online (Sandbox Code Playgroud)

您会注意到,它将检查集合是否已初始化,以便我们知道何时检查数据库中的分页列表或何时仅使用当前内存对象。

现在您已准备就绪,只需将模型上当前的 IList 引用更改为 IPgedList,然后将 NHibernate 映射到新的自定义集合,使用如下所示的流畅 NHibernate,就可以开始了。

.CollectionType<PagedListFactory<Recipient>>()
Run Code Online (Sandbox Code Playgroud)

这是该代码的第一次迭代,因此需要一些重构和修改才能使其完美。

我目前唯一的问题是,它不会按照映射文件建议的父子关系顺序获取分页项目。我已经向地图添加了 order-by 属性,但它不会关注它。每个查询中的任何其他 where 子句都没有问题。有谁知道为什么会发生这种情况以及是否有任何相关情况?如果我不能解决这个问题,我会感到失望。