TList<Entity> (Tips and Tricks)
Utilizing many new features from the .Net 2 framework (Generics, Delegate and Anonymous Methods) we were able to greatly improve some core functionalities of the templates including Searching, Filtering and Sorting.
1. Find Methods
Old Implementation
When using the Find method in .netTeirs 1, the entity search was done with this kind of method call:
Method Signature: Find (EntityColumn column, object searchCriteria);
Example A:
ProductCollection productCollection = products.Find(ProductColumn.ProductId, 1);
this looks very clean but actually it's mostly inefficient (try it in a 100x loop, with a 1000 item list ;-) the reason is that it use internally reflection to get the right property and its value, and then do the comparison.
New Implementation
In .netTiers2, the Find method has a new overload that take a generic delegate as parameter.
Method Signature: Find(Predicate<T> match);
Example B:
TList<Product> products = DataRepository.ProductProvider.GetAll();
void UpdateProductQuantity(int productId, int newQuantity)
{
Product product = products.Find(delegate (Product p) {return p.ProductId == productId;});
product.Quantity = newQuantity;
}
See how the use of an anonymous method for the predicate allow us to use the current context (here the productId parameter of the UpdateProductQuantity method).
To search for several items that match the predicate, just use the FindAll method.
You can find more information about the Predicate Generic Delegate on msdn2.
2. Filtering
The Filtering is used to filter a given list of entities, this is very usefull when the list is binded to a visual control like the DataGridView for example. Filtering is done by providing a set of filter criteria, which is then applied to the list. The items that DO NOT match the criteria are removed temporarly from the collection's innerList and put in the FilteredItems property. The filter can finally be removed by calling the RemoveFilter() method.
Old Implementation
In netTiers1, filtering was done like so:
Example C:
products.Filter = "ProductName = 'Sugar' AND CategoryId = 5";
While it tried to emulate a familiar SQL syntax for where clauses, a special parser was evaluating the filter expression, and then use reflection to check property value; the result was a very slow and very limited filtering (due to the filter parser limitations and the heavy use of reflection).
New Implementation
With the use of the new Predicate<T> overload, you can do:
Example D:
product.ApplyFilter(delegate(Product p) {return p.ProductName == "Sugar" && p.CategoryId ==5;}));
3. Sorting
Following a familiar pattern now, with the help of the comparison generic delegate.
Method Signature: Sort(Comparison<T> match);
We can create more efficent and complex sorting, for example, say that we want to sort the northwind category list based on the child ProductCollection property Count.
Example E:
We could do something like the following:
category.Sort(MyCustomSort); //uses the MyCustomSort delegate
...
public int MyCustomSort(Category c1, Category c2)
{
return c1.ProductCollection.Count.CompareTo(c2.ProductCollection.Count);
}
Similarly, like in the previous examples of Find and Filter, we could've also used an anonymous delegate.
category.Sort(
MyCustomSort(Category c1, Category c2){
return c1.ProductCollection.Count.CompareTo(c2.ProductCollection.Count);
});
You can find more information about the Comparing and Generic delegates on MSDN2.
4. Action
This last point is dedicated to a small tip i really like :-)
The Action generic delegate that is used on the ForEach method of the TList collections.
Example F:
category.ProductCollection.ForEach(delegate(Product p) {Console.WriteLine(p.ProductName);});
Example G:
int total = 0;
order.OrderDetailCollection.ForEach(delegate(OrderDetail od) {total += od.Quantity * od.UnitPrice ;});
You can find more information about the Action Generic Delegate on MSDN2.
That's all! Good Luck!
Cheers!
John Roland / Robert Hinojosa - NetTiers.com