Here I will post problems I and my colleagues met and solutions we found.

Sunday, January 11, 2009

Lazy loading for CSLA lists to support Server mode in DevExpress Grid. Part 1

In one of our WinForms projects, I implemented so-called "lazy loading" for CSLA lists. We were very pleased with the results, so I decided to describe what was done.

First, let's state the problem I'm solving. We have classical client-server (and this is important, to make it work for n-tier, it would need to be modified) application and we want to display list of some objects, let's say customers. The list can be quite long, like 60K records. When I tried to populate that list, it took quite a long time, more than 10 seconds.

Now, we used DevExpress grid in our application that supported Server mode. To use this we would have to implement IListServer interface. The version of CSLA we used at the moment was 3.0.3

First, to avoid dependencies on user interface logic from my business layer, new interface was introduced, which is copied from IListServer.



/// <summary>
/// ILazyLoading interface is needed to support lazy loading, or loading on demand
/// </summary>
public interface ILazyLoading
{
/// <summary>
/// Number of all object in the list, including not loaded
/// </summary>
int Count { get;}

/// <summary>
/// Returns object by index. If object wasn't loaded before, it has to be loaded here
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
object this[int index] { get; set;}
/// <summary>
/// Get row index by unique id
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
int GetRowIndex(object key);
/// <summary>
/// Get unique id of the row by index
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
object GetRowKey(int index);
/// <summary>
/// Add object to list
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
int Add(object value);
/// <summary>
/// Clear
/// </summary>
void Clear();
/// <summary>
/// Contains
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
bool Contains(object value);
/// <summary>
/// IndexOf
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
int IndexOf(object value);
/// <summary>
/// Insert
/// </summary>
/// <param name="index"></param>
/// <param name="value"></param>
void Insert(int index, object value);
/// <summary>
/// Same as IList.IsFixedSize
/// </summary>
bool IsFixedSize { get;}
/// <summary>
/// Same as IList.IsReadOnly
/// </summary>
bool IsReadOnly { get;}
/// <summary>
/// Remove
/// </summary>
/// <param name="value"></param>
void Remove(object value);
/// <summary>
/// RemoveAt
/// </summary>
/// <param name="index"></param>
void RemoveAt(int index);
/// <summary>
/// ApplySort
/// </summary>
/// <param name="sortInfo"></param>
void ApplySort(ListSortDescriptionCollection sortInfo);
/// <summary>
/// Same as IBindingList, but need to override it to change indexes
/// </summary>
event ListChangedEventHandler ListChanged;
}


The next step is implementing this. There were two ways doing this. One is without modified CSLA library by putting implementation into my base objects. The disadvantage of this approach is that it would require repeating everything for read-only and base lists. So, I decided to not bother with that and put my implementation directly into source code, making it as less intrusive as possible. Which means I modified ExtendedBindingList little bit.

No comments: