For those of you who don't use LLBL Gen Pro, it generates Entity objects for you, one for each of the tables in your database. You can have it do more then that, but it can do that much simply by reverse engineering your database. It also creates strongly typed collections for each of these entities.
On the surface the collections work about as you expect. You can get any of the elements in the collection by index, you can iterate over them using For/Each, you can Add and Remove entities, you can load them using a filter, etc. They add another nifty feature not normally found on collections, and that is a .Sort method.
It isn't terribly well documented that access to the collection is actually granted through a DefaultView property on the collection, you don't have direct access to the collection. LLBL creates views that are very similar in function to the DataViews that Microsoft implements for their DataTables. The DefaultView is simply a view that is always present on the collection. This view starts with a blank filter (show everything in the collection) and a blank sort (show the entities in the order they were put into the collection). By simply changing either the Filter or the Sort properties on the DefaultView though, you can get very different behavior from your collections. You can also define additional view objects and attach them to the collection so you can have multiple views of the same list at the same time.
Of course I don't bother writing about this kind of stuff unless I got tripped and thrown against the wall at some point while using it. So here's the WTF for today.
I built a subroutine that accepted an IEntityView (generic interface for views) as a parameter. This subroutine was responsible for taking the view, which contained a list of properties that needed to be displayed on the form, and converting that list to actual controls and adding them to the page. A sort was applied to this view so that the controls showed up in the right order, and then the view was passed to the routine for processing.
SetupItemEnt.SetupEntity.SetupEntityDetail.DefaultView.Sorter = MySortExpression
'Sort is correct here...
BuildTableRowsForEntity(SetupItemEnt.SetupEntity.DefaultView)
The really weird part is that the sort didn't survive the passoff. It was there right before I called the subroutine, and on the first line of the subroutine it wasn't anymore.
Protected Sub BuildTableRowsForEntity(ByVal SetupEnt As ORMSupportClasses.IEntityView)
'Sort is gone, using database order now...
End Sub
When I switched the code to pass the entire entity collection (instead of the default view on that collection), everything started working.
SetupItemEnt.SetupEntity.SetupEntityDetail.DefaultView.Sorter = MySortExpression
'Sort is correct here...
BuildTableRowsForEntity(SetupItemEnt.SetupEntity)
Protected Sub BuildTableRowsForEntity(ByVal SetupEnt As LWS_DAL.EntityClasses.SetupEntityEntity)
'Sort is here now...
End Sub
I tried changing the parameter to passing by reference instead of by value, it didn't make a difference. The only thing I can think of is that the .DefaultView property must be somehow passing a different instance of itself to the subroutine then the one that I applied the sort to, but for the life of me I can't see why it would. I've passed entity views around before and it seems to work fine. This is the first (and last) time I ever tried passing the .DefaultView as a parameter though.
So, what I learned today is...
- Don't pass a entitycollection.DefaultView as a parameter if it is sorted, the sort gets lost
Update: The catch with DefaultViews is that they are not persistently conected to the collection, but are instead generated at request. This means that every call to the .DefaultView property returns a new view, not the one that you got last time. Incidently this is also why a 2 column sort never works when using the DefaultView; It gets an instance of the view, sorts the view by the first column, throws away the first view and gets a new instance, then sorts by the second column.