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 ImplementationWhen 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 ImplementationIn .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 ImplementationWith 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
PingBack from http://ccgi.densen.plus.com/2006/04/11/tlist-net-tiers-tips/
Pingback from Phil Bernie Consulting » 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