CodeSmith Community
Your Code. Your Way. Faster!

TList<Entity> (Tips and Tricks)

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


Posted Mar 09 2006, 10:36 PM by dSquared

Comments

jamest wrote re: TList&lt;Entity&gt; (Tips and Tricks)
on 03-12-2006 9:19 AM
Good tips!

Unfortunately I am trying to apply filtering without success. Could you pelase provide me a VB.NET sample code how I can apply filtering as my application is written in VB.NET.

product.ApplyFilter(delegate(Product p) {return p.ProductName == "Sugar" && p.CategoryId ==5;}));


Thanks!
James T.
BioMash wrote re: TList&lt;Entity&gt; (Tips and Tricks)
on 03-13-2006 1:25 AM
Great! Very helpful

Thanks.

John.

catsclaw wrote re: TList&lt;Entity&gt; (Tips and Tricks)
on 03-13-2006 2:13 PM
I agree these tips are great!

I'd love to see some VB.NET versons of some of this code too.  I got a response on one of the forums for the ForEach in vb.net

product.ForEach(New Action(Of ContentQuality)(AddressOf product.ForEachSomething))

Sub ForEachSomething(ByVal p as Product)
'some code
End Sub
The Prisoner wrote re: TList&lt;Entity&gt; (Tips and Tricks)
on 06-13-2006 1:57 PM
removefilter doesn't seem to work
TList Net Tiers Tips at Densen wrote TList Net Tiers Tips at Densen
on 01-03-2007 3:54 PM
Phil Bernie Consulting » Using Predicate Generic Delegates in VB.Net with .NetTiers wrote Phil Bernie Consulting &raquo; Using Predicate Generic Delegates in VB.Net with .NetTiers
on 08-01-2007 8:23 AM

Pingback from  Phil Bernie Consulting &raquo; Using Predicate Generic Delegates in VB.Net with .NetTiers

ParisianBull wrote re: TList<Entity> (Tips and Tricks)
on 09-10-2007 11:18 AM

First and foremost: Thanks for good tips!

However, I must take issue with one thing. The impression is created that the flexibility offered by Find() and other methods taking delegates could not have been provided in .NET 1.x, but that is plainly not the case. The exact same functionality could be provided by defining an interface with one method in place of the delegate. The main difference is coding convenience, since anonymous methods can be written inline, and since using an interface means one would have to decorate the implementing class appropriately.

On a side not, I believe it is less efficient to invoke a delegate than calling a method on an interface, although the difference may not matter in many cases. (Reflection is certainly much more expensive anyway.)

ParisianBull wrote re: TList<Entity> (Tips and Tricks)
on 09-10-2007 11:22 AM

Also, as I see several people doing this, the ForEach method is plainly a bad idea. It provides no extra functionality compared to the foreach STATEMENT, but it DOES add a lot of overhead as now the delegate must be invoked once per item in the list.

I fail to see how the use of the delegate improves on the straightforward implementation:

int total = 0;

foreach (OrderDetails d in order.OrderDetailCollection)

  total += d.Price * d.Quantity;

Copyright © 2008 CodeSmith Tools, LLC
Powered by Community Server (Commercial Edition), by Telligent Systems