Implementing IPagedList<T> on my models using NHibernate - c#

I have found when using NHibernate and creating a one to many relationship on an object that when the many grows very large it can slow down dramatically. Now I do have methods in my repository for collecting a paged IList of that type, however I would prefer to have these methods on the model as well because that is often where other developers will look first to gather the list of child objects.
e.g.
RecipientList.Recipients will return every recipient in the list.
I would like to implement a way to add paging on all of my oen to many relationships in my models using preferably an interface but really anything that won't force a typed relationship onto the model. For example it would be nice to have the following interface:
public interface IPagedList<T> : IList<T>
{
int Count { get; }
IList<T> GetPagedList(int pageNo, int pageSize);
IList<T> GetAll();
}
Then being able to use it in code...
IList<Recipient> recipients = RecipientList.Recipients.GetPagedList(1, 400);
I have been trying to think of ways to do this without giving the model any awareness of the paging but I'm hitting my head against a brick wall at the moment.
Is there anyway I can implement the interface in a similar way that NHibernate does for IList and lazyloading currently? I don't have enough knowledge of NHibernate to know.
Is implementing this even a good idea? Your thoughts would be appreciated as being the only .NET developer in house I have no-one to bounce ideas off.
UPDATE
The post below has pointed me to the custom-collection attribute of NHibernate, which would work nicely. However I am unsure what the best way is to go around this, I have tried to inherit from PersistentGenericBag so that it has the same basic functionality of IList without much work, however I am unsure how to gather a list of objects based on the ISessionImplementor. I need to know how to either:
Get some sort of ICriteria detail for the current IList that I am to be populating
Get the mapping details for the particular property associated with the IList so I can create my own ICriteria.
However I am unsure if I can do either of the above?
Thanks

Ok I'm going to post this as an answer because it is doing mostly what I wanted. However I would like some feedback and also possibly the answer to my one caveat of the solution so far:
I've created an interface called IPagedList.
public interface IPagedList<T> : IList<T>, ICollection
{
IList<T> GetPagedList(int pageNo, int pageSize);
}
Then created a base class which it inherits from 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;
}
}
}
I then create an IUserCollectionType for NHibernate to use as the custom collection type and NHPagedList which inherits from PersistentGenericBag, IPagedList as the actual collection itself. I created two seperate classes for them because it seemed like the use of IUserCollectionType had no impact on the actual collection to be used at all, so I kept the two pieces of logic seperate. Code below for both of the above:
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 next:
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;
}
}
}
You will notice that it will check to see if the collection has been initialized or not so that we know when to check the database for a paged list or when to just use the current in memory objects.
Now you're ready to go, simply change your current IList references on your models to be IPagedList and then map NHibernate to the new custom collection, using fluent NHibernate is the below, and you are ready to go.
.CollectionType<PagedListFactory<Recipient>>()
This is the first itteration of this code so it will need some refactoring and modifications to get it perfect.
My only problem at the moment is that it won't get the paged items in the order that the mapping file suggests for the parent to child relationship. I have added an order-by attribute to the map and it just won't pay attention to it. Where as any other where clauses are in each query no problem. Does anyone have any idea why this might be happening and if there is anyway around it? I will be disappointed if I can't work away around this.

You should look into one of the LINQ providers for NHibernate. What your looking for is a way to delay-load the results for your query. The greatest power of LINQ is that it does exactly that...delay-loads the results of your queries. When you actually build a query, in reality its creating an expression tree that represents what you want to do, so that it can actually be done at a later date. By using a LINQ provider for NHibernate, you would then be able to do something like the following:
public abstract class Repository<T> where T: class
{
public abstract T GetByID(int id);
public abstract IQueryable<T> GetAll();
public abstract T Insert(T entity);
public abstract void Update(T entity);
public abstract void Delete(T entity);
}
public class RecipientRepository: Repository<Recipient>;
{
// ...
public override IQueryable<Recipient> GetAll()
{
using (ISession session = /* get session */)
{
// Gets a query that will return all Recipient entities if iterated
IQueryable<Recipient> query = session.Linq<Recipient>();
return query;
}
}
// ...
}
public class RecipientList
{
public IQueryable<Recipient> Recipients
{
RecipientRepository repository = new RecipientRepository();
return repository.GetAll(); // Returns a query, does not evaluate, so does not hit database
}
}
// Consuming RecipientList in some higher level service, you can now do:
public class RecipientService
{
public IList<Recipient> GetPagedList(int page, int size)
{
RecipientList list = // get instance of RecipientList
IQueryable<Recipient> query = list.Recipients.Skip(page*size).Take(size); // Get your page
IList<Recipient> listOfRecipients = query.ToList(); // <-- Evaluation happens here!
reutrn listOfRecipients;
}
}
With the above code (its not a great example, but it does demonstrate the general idea), you build up an expression representing what you want to do. Evaluation of that expression happens only once...and when evaluation happens, your database is queried with a specific query that will only return the specific subset of rows you actually requested. No need to load up all the records, then filter them down later on to the single page you requested...no waste. If an exception occurs before you evaluate, for whatever reason, you never even hit the database, increasing efficiency even more.
This power can go much farther than querying a single page of results. The extension methods .Skip() and .Take() are available on all IQueryable<T> and IEnumerable<T> objects, along with a whole bunch of others. In addition, you have .Where(), .Except(), .Join(), and many, many more. This gives you the power to, say, .GetAll(), then filter the possible results of that query with one or more calls to .Where(), finishing with a .Skip(...).Take(...), ending in a single evaluation at your .ToList() (or .ToArray()) call.
This would require that you change your domain somewhat, and start passing IQueryable<T> or IEnumerable<T> around in place of IList<T>, and only convert to an IList<T> at your higher-level, 'publicly facing' services.

If you are going to do something like that, I can not think of a way, you would be able to "write" to the paged collection for NH to persist. The paged collection will be read only.
If that is ok, then you could use an approach like this: http://www.acceptedeclectic.com/2007/12/generic-custom-nhibernate-collections.html
He's wrapping the PersistentGenericBag and is adding some ekstra methods, just like you describe. GetPagedList() could then be implemented with a criteria, that return an ReadOnlyCollection, as could Count - returning a long of course. The GetAll() method won't be neccessary, it will just be returning the collection it self, as far as I can see.
As for if it's a good idea, I do think it is, if you have a lot of collections, where this is an actual problem. If it's just one or two collctions, I would go with just having a method on the entity it self, that returned the collection in pages.

Related

Interface reference that specifies I need an object implementing 2 or more interfaces

Let us say I have this overly simple code here:
class Person
{
public int age;
public string name;
public Person(int age, string name)
{
this.age = age;
this.name = name;
}
}
public class MySimpleDatabase
{
List<Person> people;
internal List<Person> People
{
get
{
if(people == null)
{
people = new List<Person>();
people.Add(new Person(24, "ASD"));
people.Add(new Person(35, "QWE"));
people.Add(new Person(12, "MNB"));
}
return people;
}
}
}
public class ProcessPeopleConcrete
{
public void WriteNames()
{
List<Person> people = new MySimpleDatabase().People;
foreach (var person in people)
{
Console.WriteLine(person.name);
}
}
}
public class ProcessPeopleInterface
{
public void WriteNames()
{
//question for here.
IEnumerable<Person> people = new MySimpleDatabase().People;
foreach (var person in people)
{
Console.WriteLine(person.name);
}
}
}
Here I have the concrete processor as well as the interface based one. Here the interface processor is more maintainable of course, but as far as I know
//edited here to clarify
I can specify only one type for a variable that I require, in my case it is the IEnumerable<Person>.
What if I need something there that implements not one, but two interfaces at the same time, that have nothing to do with each other (one doesn't implement the other)?
So say I need any collection that has to implement both ICloneable and IEnumerator. In a comment it was put correctly that I could define another interface that implements both of them. But if I use pre-defined collections, I can't do that becuase then I won't be able to toss any of them as they obviously don't implement my custom made interface.
What sort of type would I specify in this case to my variable people (commented with "question here")? If there was a variable declaration like <IEnumerable, ICloneable> people; that would imaginarily mean I need something that implements both IEnumerable and ICloneable. But is there a language feature similar to that or it is what I said it is - imaginary only?
As you have figured out, you cannot force classes to implement interfaces which they don't ;)
You have also noted that interfaces are used to solve a specific problem. In one case they solve how collections can be enumerated, and in the other case they solve how an object can be cloned.
From your question I take it that you want to be able to tell that the returned object solves both problems and you wonder how you can tell that in the method contract.
You do it by defining a new interface:
public interface ISuperClonableList<T> : IEnumerable<T>, IClonable
{
}
That's it.
If the list itself isn't clonable you need to wrap it in a new class which implements both interfaces. Pass the actual list as a constructor parameter and call it in every IEnumerable method implementation.
The problem with cloning interfaces is that they typically do not specify if it should be a deep or shallow clone. It's important to know that since it can cause large problems if the contained items are mutable.
Example generated from ReSharper:
public class MyListWrapper<T> : ISuperClonableList<T>
{
private readonly ISuperClonableList<T> _innerList;
public MyListWrapper(ISuperClonableList<T> innerList)
{
_innerList = innerList;
}
public IEnumerator<T> GetEnumerator()
{
return _innerList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable) _innerList).GetEnumerator();
}
public void Add(T item)
{
_innerList.Add(item);
}
public void Clear()
{
_innerList.Clear();
}
public bool Contains(T item)
{
return _innerList.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_innerList.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
return _innerList.Remove(item);
}
public int Count
{
get { return _innerList.Count; }
}
public bool IsReadOnly
{
get { return _innerList.IsReadOnly; }
}
public int IndexOf(T item)
{
return _innerList.IndexOf(item);
}
public void Insert(int index, T item)
{
_innerList.Insert(index, item);
}
public void RemoveAt(int index)
{
_innerList.RemoveAt(index);
}
public T this[int index]
{
get { return _innerList[index]; }
set { _innerList[index] = value; }
}
}
This might not exactly be what you are looking for, but here's something similar to you concept. I created a simple function accepting a Tuple of IEnumerable and IList, then you can feed arguments to it:
public static void Foo(Tuple<IEnumerable<int>, IList<int>> complex)
{
foreach (var item in complex.Item1)
{
Console.WriteLine(item.ToString());
}
complex.Item2.Add(9);
}
A simple list:
List<int> ints = new List<int>
{
1,
3,
5,
7
};
The function is then invoked by either first instantiating a separate variable, as I did, or writing the instantiation right into the Foo() function.
Tuple<IEnumerable<int>, IList<int>> tuple = Tuple.Create((ints as IEnumerable<int>), (ints as IList<int>));
Foo(tuple);
I'm also interested in a real solution though, provided that there is one.

How can I get a unique id for a List<T>

I have a List<T>, where T is a class that has an int field for an id. How is the best way to get a unique id value that has not been used in any of the objects in the List<T>?
How is this procedure normally coded? Is there a data type that can help with this or do I need to store the largest id value?
EDIT
How about when I get an id for an object that is 1. I then delete the object from the List. When I create a new object, I would like the unique id to be 2. In this situation, is there any better way than to store the last unique id?
Thanks.
For that approach I'd write an inherited class of List<T> which holds the logic, so you wouldn't need to implement it everywhere you access the list.
You can even leave it generic if you have a minimum interface which has the Id value.
interface IWithId {
int Id { get; set; }
}
class CustomList<T> : List<T> where T : class, IWithId {
private lastUsedId = 1;
public void AddObjectWithAutomaticId(T newObject) {
newObject.Id = lastUsedId++;
base.Add(newObject);
}
public T GetElementById(int id) {
return base.SingleOrDefault(p => p.Id == id);
}
}
The Remove method would still work as before. The class stores the last used Id, independent what you remove. The Add method is also still available, when you want to add an object with a given Id and not auto-fill it.
I agree with the comment that a GUID would suit you as an id property. If, however, you need to use an int then I suggest a new class.
The problem with inheriting List<T> is that you would have to override multiple methods to ensure that things such as Add(), AddRange(), Insert() can't add duplicate ids and update the stored maximum id. It would be easy to miss one.
I would use a class which doesn't inherit anything, but uses a dictionary internally. This won't have all the same methods as a List<T>, but that's not necessarily a bad thing - it saves mistakes being made and you can have a ToList() method for when they want to query it as if it was a List<T>.
Using part of a previous answer to ensure that T has an Id property gives:
interface IHasId {
int Id { get; set; }
}
class AutoIdList<T> where T : class, IHasId {
private readonly IDictionary<int, T> _dictionary = new Dictionary<int, T>();
//Using this list ensures you don't duplicate ids even
//for an item added with an explicit id then removed
private IList<int> _historicalIds = new List<int>();
private int highestAutoGeneratedId = 0;
public List<T> ToList() {
return _dictionary.Values.ToList();
}
public void Add(T item, bool generateId) {
if (generateId) {
highestAutoGeneratedId = NextId();
T.Id = highestAutoGeneratedId;
}
Add(T);
}
public void Replace(T item) {
_dictionary[item.Id] = item;
}
public void Remove(T item) {
_dictionary.Remove(item.Id);
}
private void Add(T item) {
if (_historicalIds.Contains(T.Id)) {
//throw an appropriate exception
} else {
_historicalIds.Add(T.Id);
_dictionary.Add(T.Id, T);
}
}
private int NextId() {
var id = highestAutoGeneratedId + 1;
while (_historicalIds.Contains(id)) {
id++;
}
return id;
}
//More methods to simulate AddRange, Insert, etc if required. Leave if not.
//Should all have simple logic but require checking of Id if adding anything
//Also need logic to maintain the list of used ids
}

Design pattern for filtering/counting a collection in various states/steps

I'm starting with an IEnumerable and want to run it through several methods that contain LINQ-to-SQL queries, which will filter the result set. Some methods will operate on the original result set, others will operate on a further-filtered result set. However, I want to retain a count of the Excepts (anti-intersections?) of the supplied IEnumerable A and the filtered IEnumerable B so the counts can be sent in an email at the end of all filtering methods. For instance, if Method A is provided a collection of 60 records, but after filtering, the result is down to 20 records, I want to store the number 40 somewhere.
What is the recommended way of keeping track of the counts and collections/queries? I was thinking of using IQueryable and doing Count() within the methods with an out parameter to track the counts, but that just seems messy. Is there some sort of design pattern that fits this process?
interface IFilter<T>
{
IQueryable<T> Filter(IQueryAble<T> data);
}
interface IResultSet<T>
{
int OrignalCount { get; }
int FilteredCount { get; }
IEnumerable<T> Result { get; }
void AddFilter(IFilter<T> filter);
}
and the implementation of IResultSet:
class ResultSet<T> : IResultSet<T>
{
private IQueryable<T> data;
private List<IFilter> filters = new List<IFilter>();
public int OriginalCount {get; private set;}
public int FilteredCount
{
get { return Result.Count(); }
}
public IEnumerable<T> Result
{
get
{
IQueryable data = this.data;
foreach(IFilter filter in filters)
{
data = filter.Filter(data);
}
return data;
}
}
//constructor
public ResultSet<T>(IQueryable<T> data)
{
this.data = data;
this.OriginalCount = data.Count();
}
public void AddFilter(IFilter<T> filter)
{
this.filters.Add(filter);
}
}

Using LINQ with wrapped arrays

I'm new to LINQ and I'm doing a simple project to learn the features of the technology.
Currently I've got a static class that wraps an array of object (a kind of simple factory). Let's say it looks like the following:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
// ...
}
Now I can add some functions to my Factory that allow me to query the inner array, e.g.
public static Item GetByID(ItemID id)
{
var query =
from item in items
where item.ID == id
select item;
return query.First();
}
However, this requires me to modify the internals of the Factory class. Is there a way to write such queries from the 'outer world' instead ?
public class OtherClass
{
var result = from it in Factory select ...
}
?
Yes, you can. Just use linq on the Factory from the 'outer world':
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Items.SingleOrDefault(i => i.ID == id);
}
}
Of course, to do this, you'd need to change the access modifier of the items array to be public.
There are so many options.
The easiest thing to do is just to expose a public property that allows just what you want to have allowed:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
public static IEnumerable<IReadableItem> Items{ get { return items; } }
// ...
}
The above code assumes that the Item class implements an IReadableItem interface that only has the methods and properties on it that you want to allow people to access. You could also clone the items list before returning it each time, if you're worried someone might re-cast the Items or try to modify it using reflection. Because the standard LINQ methods all work off of IEnumerable<>s, this would allow someone to effectively produce a LINQ query on your items, without exposing overmuch data.
List<string> bestItemNames = Factory.Items.Where(i => i.IsBest)
.Select(i => i.Name)
.ToList();
If you wanted to get really fancy, you could even implement your own LINQ provider. From a language perspective, LINQ expression syntax just maps to specific method names, so if you had a class that implemented a .Where() and a .Select() method, then you could implement that pretty much however you wanted, and people wouldn't know any different until they tried doing something that your methods didn't support.
One possibility is to implement IQueryable<T> for a non-static class:
public class Factory<T> : IQueryable<T>
{
protected T[] _items = new T[]{};
public Type ElementType
{
// or typeof(T)
get { return _items.AsQueryable().ElementType; }
}
public System.Linq.Expressions.Expression Expression
{
get { return _items.AsQueryable().Expression; }
}
public IQueryProvider Provider
{
get { return _items.AsQueryable().Provider; }
}
public IEnumerator<T> GetEnumerator()
{
return ( IEnumerator<T> )_items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
}
Derive non-generic class to populate array (if desired)
public class ItemFactory : Factory<Item>
{
public ItemFactory()
{
// items are created here
}
}
Create static instance
public static class Factories
{
private static ItemFactory _itemFactory = new ItemFactory();
public static ItemFactory ItemFactory { get { return _itemFactory; } }
}
Usage:
var specificItem = Factories.ItemFactory
.Where( item => item.ID == id )
.SingleOrDefault();
use an expression tree
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Get(i => i.id == id);
}
}
and change the get method to
public Item Get(Expression<Func<Item,bool>> filter)
{
return items.SingleOrDefault(filter);
}
however, this approach makes little sense unless you are encapsulating some other logic in your factory class i.e. select only rows that are not soft deleted.

How can I extend IEnumerable<T> to load my collection from a web service?

I've been trying to puzzle out how I could implement Enumerable<T>/IEnumerator<T> to satisfy the following:
I call a web service to create a query
I poll the web service to find out when it is ready to return results
Once the web service is ready to return results, I call a method (e.g. GetNext(n)) to get n items from it
Once GetNext(n) returns less than n results I have retrieved all of my items.
I'm having some difficulty trying to figure out how I could make an IEnumerable handle all of the heavy lifting from me and the MSDN IEnumerable documentation has not helped.
Here is a simplified version of my code:
public class MyEnumerable : IEnumerable
{
private MyWebService _service;
private int _queryID;
public MyEnumerable(MyWebService service, int queryID)
{
_service = service;
_queryID = queryID;
}
IEnumerator IEnumerable.GetEnumerator()
{
return new MyEnumerator(_service, _query);
}
}
public class MyEnumerator : IEnumerator
{
private List<QueryResult> _items; //want to load my items from WebService into this
private MyWebService _service;
private int _queryID;
private int _index = 0;
private MyEnumerator(MyWebService service, int queryID)
{
_service = service;
_queryID = queryID;
}
public object Current
{
//what goes here?
}
public bool MoveNext()
{
//what goes here? would I call the web service here?
}
public void Reset()
{
_index = 0;
}
}
Hopefully this makes a bit more sense. Let's assume I can call a method on my webservice called GetNext(n).
Rather than explicitly implementing the interface, unless you have a reason not to, you should generally use an iterator block to create such sequences. It will take care of the boilerplate code, just leaving you with the interesting implementation. A problem like this will generally look something along these lines:
//you can make this private if you want
public static IEnumerable<IList<Foo>> GetPages(int pageSize)
{
IList<Foo> nextGroup = ExecuteQuery();
while (nextGroup.Count == pageSize)
{
yield return nextGroup;
nextGroup = ExecuteQuery();
}
if (nextGroup.Any())
yield return nextGroup;
}
You can then use SelectMany to flatten out the list of groups into a list of the individual items:
public static IEnumerable<Foo> GetItems(int pageSize)
{
return GetPages(pageSize).SelectMany(x => x);
}
Use Rx Reactive Extensions, and the Buffer extension method. (Meaning, IObservable rather than IEnumberable). Seems to match your use case perfectly!

Categories