Introduction
In this article, I introduce a way to use a type of object factory as a sortable, filterable, memory resident data source. Why would you want to do this? Well, if you want to work disconnected from your database and still want to be able to provide a data source that you can sort and filter on by calling simple public methods, then this will work for you.
Make some kind of an object
First of all, we need an object. Just an object that we may want to carry around our application. Let's start with a simple User
class. In the context of this example, I tend to think of our object as a mobile database record. One record in the many that we may want to sort or filter on.
namespace Slade
{
public class User
{
private string _firstName;
private string _lastName;
public User(string firstName, string lastName)
{
_firstName = firstName;
_lastName = lastName;
}
public string FirstName
{
get
{
return _firstName;
}
}
public string LastName
{
get
{
return _lastName;
}
}
}
}
Our mobile object database
Now we need the mobile object database class that will be responsible for the following tasks:
- Create a
User
object for each row in the user table of our database
- Store the collection of these objects
- Provide a means of sorting on one or more of the object's properties
- Provide a means of filtering on one or more of the object's properties
For simplicity, I have substituted using a database with baking the collection of User
s straight into the class. Normally, the User
s would be built by getting the details from the return of the stored procedure and then simply making a user for each record.
Let's begin this class by making our User
collection in the UserMobileDatabase
.
using System;
using System.Collections;
namespace Slade
{
public class UserMobileDatabase
{
ArrayList _userCollection;
public UserMobileDatabase()
{
_userCollection = new ArrayList();
}
public void MakeUsers()
{
User user1 = new User("Roger", "Rogerson");
_userCollection.Add(user1);
User user2 = new User("Eric", "Ericson");
_userCollection.Add(user2);
User user3 = new User("Richard", "Richardson");
_userCollection.Add(user3);
User user4 = new User("Bob", "Bobson");
_userCollection.Add(user4);
User user5 = new User("Ronald", "Rogerson");
_userCollection.Add(user5);
}
}
}
Our first object data source
We now have a data source. An array list of objects can be bound to a DataGrid
or most other .NET bindable controls. But what if we need the flexibility of sorting like we have in the DataView
.
Sorting our collection
You may have seen this before. What we need to be able to do now is sort our custom ArrayList
of User
objects. In order to sort a custom ArrayList
, the .NET Framework needs to know what to compare. We therefore need to write a new class that implements the IComparer
interface to compare properties of two User
objects.
using System;
namespace Slade
{
public sealed class UserLastNameComparer : System.Collections.IComparer
{
public int Compare(User first, User second)
{
Slade.User firstInstance = first as Slade.User;
Slade.User secondInstance = second as Slade.User;
return firstInstance.LastName.CompareTo(secondInstance.LastName);
}
}
}
We can then pass the ArrayList.Sort
command our new custom comparer.
Implementing our sorting feature
Now we are ready to add the first interesting feature to our mobile object database. The ability to sort User
objects by User.LastName
. Let's add the following method to our UserMobileDatabase
class.
public ArrayList ReturnUsers_SortByLastName()
{
if(_userCollection==null)
{
return new ArrayList();
}
else
{
UserLastNameComparer lastNameComparer = new UserLastNameComparer();
_userCollection.Sort(lastNameComparer);
return _userCollection;
}
}
Of course, we could add a comparer for the User.FirstName
as well which would be done in exactly the same way. But instead, let us not dwell on one subject. We can now move onto filtering our records.
A distinct list of names
Imagine now that for some reason, we need to provide a distinct list of last names. Perhaps for a drop down list. We need then to be able to filter our list of User
objects by last name, but only return the distinct ones. Our distinct last names are:
- Bobson
- Ericson
- Richardson
- Rogerson
Let's use a little used feature of the ArrayList
; the BinarySearch
method. The BinarySearch
algorithm allows us to locate specific elements in our ArrayList
as long as it has been sorted first. So let's use it here. First we will sort our ArrayList
by calling the ReturnUsers_SortByLastName()
method. We can then use BinarySearch
to look for unique last names and return a new ArrayList
of last name string
s that can be bound to our drop down list.
public ArrayList ReturnDistinctLastNames()
{
ArrayList distinctNames = new ArrayList();
foreach(Slade.User u in this.ReturnUsers_SortByLastName())
{
if(distinctNames.BinarySearch(u.LastName)<0)
{
distinctNames.Add(u.LastName.ToString());
}
}
return distinctNames;
}
Retrieving a single user object from our names list
If we bind the ArraList
of distinct names (remember, these are now just strings) to a drop down list or combobox, then we could find the single User
object for the corresponding index. We simply need to add a way of getting out a single User
from our UserMobileDatabase
. We would do that as easily as referencing the ArrayList
index.
public User GetSingleUser(int index)
{
try
{
return (User)_userCollection[index];
}
catch
{
return new User("No Details", "No Details");
}
}
Conclusion
I find that in ASP.NET applications, I make extensive use of objects mapped to the output of stored procedures together with these factory types that then instantiate and store groups of objects. Even if you don't use the sort and filter capabilities, this method can quickly become a neat framework for storing and obtaining object based data.