TList<Entity> (Tips and Tricks) - .netTiers Team Blog - CodeSmith Community - CodeSmith Community
Welcome to the CodeSmith Community!

TList<Entity> (Tips and Tricks)

CodeSmith Community

A description has not yet been added to this group.

TList<Entity> (Tips and Tricks)

Rate This
  • Comments 10

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

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • * Please enter your name
  • * Please enter a comment
  • Post
  • 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.
  • Great! Very helpful

    Thanks.

    John.

  • 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
  • removefilter doesn't seem to work
  • PingBack from http://ccgi.densen.plus.com/2006/04/11/tlist-net-tiers-tips/

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

  • 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.)

  • 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;

  • how can i apply filter if i deeply loaded a list.

    e.g i used like that and its not working

    product.ApplyFilter(delegate(Product p) {

    return p.productcategorySource.categoryId ==5;}));

    where productcategorySource is loaded through deepload

  • Sorry it was my mistake..... i take the categoryid as Guid and during fetching the record it was appending a huge ammount of white spaces in every record and i dont know why. when i trim both to compare and it is working fine

    Thanks

Page 1 of 1 (10 items)
Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • * Please enter your name
  • * Please enter a comment
  • Post