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 2

The general idea behind this approach was fetching primary keys first and requesting objects later. My test showed that it was many times faster to fetch primary keys into the list comparing to fetching all fields and creating objects, which wasn't a surprise.

The supporting class was created that would store the mapping between primary keys and fetched objects. That was pretty simple class:



/// <summary>
/// Controls if object is loaded
/// </summary>
[Serializable]
public class LazyLoadingController
{
[Serializable]
private class ObjectInfo
{
public object _id;
public object _loadedObject = null;

public ObjectInfo(object id)
{
_id = id;
}
public ObjectInfo(object id, object loadedObject)
{
_id = id;
_loadedObject = loadedObject;
}
}
[Serializable]
private class ObjectInfoList : KeyedCollection<object, ObjectInfo>
{
protected override object GetKeyForItem(ObjectInfo item)
{
return item._id;
}
}

#region Variables
private ObjectInfoList _idList = new ObjectInfoList();
private DateTime _lastModified = DateTime.MinValue;
#endregion

#region Public methods
public DateTime LastModified
{
get { return _lastModified; }
}
/// <summary>
/// Adds Id to the list
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public void AddId(object id, bool knownNew, DateTime lastModified)
{
if (knownNew || !_idList.Contains(id))
{
_idList.Add(new ObjectInfo(id));
if (lastModified > _lastModified)
_lastModified = lastModified;
}
}
/// <summary>
/// Adds Id to the list if needed, and marks object as loaded
/// </summary>
/// <param name="id"></param>
/// <param name="loadedObject"></param>
/// <returns></returns>
public void LoadObject(object id, object loadedObject)
{
if (_idList.Contains(id))
{
ObjectInfo objInfo = _idList[id];
objInfo._loadedObject = loadedObject;
}
else
{
_idList.Add(new ObjectInfo(id, loadedObject));
DateTime lastModified = GetObjectLastModified(loadedObject);
if (lastModified > _lastModified)
_lastModified = lastModified;
}
}

private DateTime GetObjectLastModified(object obj)
{
if (obj is IIdObject)
return ((IIdObject)obj).LastModified;
else
return DateTime.MinValue;
}
/// <summary>
/// Removes id and related object from list
/// </summary>
/// <param name="id"></param>
public void RemoveId(object id)
{
_idList.Remove(id);
}
/// <summary>
/// Marks object as not loaded
/// </summary>
/// <param name="id"></param>
public void UnLoadObject(object id)
{
if (_idList.Contains(id))
_idList[id]._loadedObject = null;
}

/// <summary>
/// Gets id and object by index
/// </summary>
/// <param name="index"></param>
/// <param name="loadedObject"></param>
/// <param name="id"></param>
public void GetObjectInfo(int index, out object loadedObject, out object id)
{
IList list = _idList as IList;
ObjectInfo info = list[index] as ObjectInfo;
loadedObject = info._loadedObject;
id = info._id;
}
/// <summary>
/// Gets index and object by id
/// </summary>
/// <param name="id"></param>
public object GetObject(object id)
{
if (_idList.Contains(id))
return _idList[id]._loadedObject;
else
return null;
}
/// <summary>
/// Gets index by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public int GetObjectIndex(object id)
{
if (_idList.Contains(id))
{
ObjectInfo objInfo = _idList[id];
return _idList.IndexOf(objInfo);
}
else
return -1;
}
/// <summary>
/// Gets list of non-loaded object ids in particular window
/// </summary>
/// <param name="startingIndex"></param>
/// <param name="count"></param>
/// <returns></returns>
public List<object> GetUnloadedIdList(int startingIndex, int count)
{
List<object> idList = new List<object>();
if (startingIndex >= _idList.Count)
return idList;
int endIndex = startingIndex + count;
if (endIndex > _idList.Count)
endIndex = _idList.Count;
IList list = _idList as IList;
for (int i = startingIndex; i < endIndex; i++)
{
ObjectInfo info = list[i] as ObjectInfo;
if (info._loadedObject == null)
idList.Add(info._id);
}
return idList;
}
/// <summary>
/// Clears everything
/// </summary>
public void Clear()
{
_idList.Clear();
}
#endregion

#region Properties
/// <summary>
/// Number of ids in the list
/// </summary>
public int Count
{
get { return _idList.Count; }
}

#endregion

}

No comments: