Dynamic Sorting, ReadOnlyListBase and LINQ

Dynamic Sorting, ReadOnlyListBase and LINQ

Old forum URL: forums.lhotka.net/forums/t/5170.aspx


raz0rf1sh posted on Tuesday, July 29, 2008

I use ReadOnlyListBase objects to display lists of data to my users.  For example, a list of customers. 

I would like to use Linq to sort the collection, and it works great!  My problem is that I would like the "order by" to be dynamic, based on a variable. 

I have looked at the Dynamic Query code provide by ScottGu, but it looks like the object has to implement IQueryable.  I notice the BusinessListBase object does implement IQueryable, just not the ReadOnlyListBase.  

I'd really like to use Linq to do this, and am interested to hear how everyone else is doing this, if they are even doing this at all.

Thanks!

RockfordLhotka replied on Tuesday, July 29, 2008

Would this help?

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

raz0rf1sh replied on Tuesday, July 29, 2008

Hi Rocky,

The problem is that the Csla.ReadOnlyListBase doesn't implement IQueryable ... which is where I am having my problem trying to work with ScottGu's code.

Thanks!

RockfordLhotka replied on Tuesday, July 29, 2008

My confusion is that his article doesn’t mention the need to override the default implementation of IQueryable.

 

ROLB does implement that interface, because it inherits (ultimately) from IEnumerable<T>, which is where Microsoft’s default implementation is hanging.

 

BLB only overrides the default IQueryable implementation because it changes the standard query behavior in a couple ways. But that should have nothing to do with standard LINQ to Objects working or not working.

 

List<T> doesn’t implement IQueryable either – it inherits it from IEnumerable<T> as well, but it seems implied that the techniques in Scott’s post would work against something like a List<T>.

 

Rocky

raz0rf1sh replied on Tuesday, July 29, 2008

I added the code to my library that inherits Csla.  My code looks like:

Aragorn.ApplicationInfoList list = null; // This inherits from My.ReadOnlyRootList, which inherits from Csla.ReadOnlyListBase

list = Aragorn.RequestProvider.ApplicationFetchList();

((IQueryable)list).OrderBy("Name");
 
I receive the following error:

Unable to cast object of type 'CreativeLogic.Aragorn.ApplicationInfoList' to type 'System.Linq.IQueryable'.

My extension method ONLY appears when I type cast my list as IQueryable.

Thanks!

RockfordLhotka replied on Tuesday, July 29, 2008

You know, I was thinking about the way they hook the extension methods to IEnumerable<T>, not IQueryable, my bad…

 

Do you have to attach your extension method to IQueryable? Can’t you attach it to a lower level list interface (IList<T> or something)?

 

Rocky

raz0rf1sh replied on Wednesday, July 30, 2008

ScottGu's code is extending IQueryable, as in:

        public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values) {

        }

Are you thinking I might be able to change this to IList<T>?

Thanks!

raz0rf1sh replied on Monday, August 04, 2008

Well ... I tried replacing IQueryable with IList ... didn't work.  So I guess I'm stuck with ObjectView.  Is there anyway Csla could include support for IQueryable in the ReadOnlyCollectionBase?

AaronErickson replied on Monday, August 04, 2008

Direct support for IQueryable should be possible, reason we have not yet has more to do with the fact that ReadOnlyListBase did not need the functionality we needed for BusinessListBase in terms of syncing the collections (i.e. add and removal tracking).  That said, if one wanted to implement this, I would start by perhaps putting the same implementation of IQueryable into ROLB that we have in BLB, which is actually pretty simple, since the real work is in CslaQueryProvider, which has the IQueryProvider implementation.

YMMV, but that is where I would start.

raz0rf1sh replied on Wednesday, August 06, 2008

My only concern with doing this is that it would make upgrading to the next version of the Csla framework a little more difficult.

Currently I have a class library that inherits from the Csla library, I'm wondering if I can just put the implementation in there.

Any other suggestions would be appreciated.

raz0rf1sh replied on Saturday, August 16, 2008

That isn't going to work either as the Csla.QueryProvider is looking for a child of type IEditableBusinessObject, which my objects are IReadOnlyObject. 

Any way we could see Linq implemented on the ReadOnlyListBast in future version of Csla?  Please! Smile [:)]

RockfordLhotka replied on Wednesday, August 20, 2008

I’ll add this to the wish list.

 

Rocky

 

From: raz0rf1sh [mailto:cslanet@lhotka.net]
Sent: Saturday, August 16, 2008 5:20 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: Dynamic Sorting, ReadOnlyListBase and LINQ

 

That isn't going to work either as the Csla.QueryProvider is looking for a child of type IEditableBusinessObject, which my objects are IReadOnlyObject. 

Any way we could see Linq implement on the ReadOnlyListBast in future version of Csla?  Please! Image removed by sender. Smile <img src=">


ozhug replied on Wednesday, August 20, 2008

Hi raz0rf1sh

I have been using ScottGu Linq Dynamic Query Code with CSLA ReadOnlyListBase

I am using this on a web page. I also do linq filtering on the list so this variable is set at the page level.

  IOrderedEnumerable<gw.dealerorders.library.ProductInfo> productfilter;

My sorting is done in the SelectObject of the CLSA datasource as below.
lv is a Listview bound to this datasource.

protected void cdsProductInfo_SelectObject(object sender, Csla.Web.SelectObjectArgs e)
{
            if (null == productfilter)
            {
                productfilter =
                       from f in GetProductList()
                       orderby f.PlatformPage, f.Title
                       select f;
            }
            var list = productfilter.AsQueryable();
            if (lv.SortExpression.Length > 1)
            {
                string sort = lv.SortExpression;
                switch (sort)
                {
                    case "Title":
                        sort = " PlatformPage, Title ";
                        break;
                }
                switch (lv.SortDirection)
                {
                    case SortDirection.Ascending:
                        list = list.OrderBy(sort + " Asc" );
                        break;
                    case SortDirection.Descending:
                        list = list.OrderBy(sort + " Desc");
                        break;
                }
            }
            e.BusinessObject = list;
        }

GetProductList() returns the ReadOnlyListBase (much the same as projectracker)

private gw.dealerorders.library.ProductInfoList GetProductList()
{
      gw.dealerorders.library.ProductInfoList  obj =         (gw.dealerorders.library.ProductInfoList)Session[PRODUCTINFO];
            if (obj == null || SupplierId != obj.SupplierId)
            {
                try
                {
                    obj = gw.dealerorders.library.ProductInfoList.GetProductInfoList(SupplierId);
                    SupplierId = obj.SupplierId;
                    Session[PRODUCTINFO] = obj;
                }
                catch (System.Security.SecurityException)
                {
                    Response.Redirect("/securityfailed.aspx");
                }
            }
            return (gw.dealerorders.library.ProductInfoList)obj;
        }

 

Hope this make sense and helps you out

 

raz0rf1sh replied on Thursday, August 28, 2008

That worked!  Thank you!  Still looking forward it be implemented directly in the ReadOnlyList! =)

setiabud replied on Thursday, March 26, 2009

I got a similar problem that is just killing me. One of my object (let's say Parent) has many children (let's call them Children - a list of Child). Parent is a Editable Root (BusinessBase) and Children is an Editable Child List and Child is EditableChild.

What I am trying to do is to do this:
Parent x = Parent.GetParent(id);
IQueryable y = Parent.MyChildren.OrderBy("Age DESC");

In theory, y then should be filled with a collection of children sorted descendingly by their age (assuming "Age" is a property of Child object).

But, what I got is that y.Count() = 0. Although if I do a Parent.MyChildren.Count() there aren't 0. Is this a bug in Dynamic LINQ or CSLA? This (the error) does not happen in readonly list for me.

For the post above, about the readonly list, you can just simply do this:

IQueryable qOL = myReadOnlyList.AsQueryable();
Then you can execute the dynamic linq query against it.

Help!
Joe

JoeFallon1 replied on Friday, March 27, 2009

Dynamic LINQ code like this works on ReadOnlyLists:

Private mSortedList As System.Linq.IQueryable

mSortedList = mList.AsQueryable.OrderBy(mSortExp & " " & mSortDirection.ToString)

dataGrid.DataSource = mSortedList.ToList

For Some reason the MS Dynamic Query Library is missing the ToList extension. So I added this to my copy:

'JF - 1/5/09 added this extension: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2666544&SiteID=1#2670101
Extension() _
Public Function ToList(ByVal query As IQueryable) As IList
Return DirectCast(Activator.CreateInstance(GetType(List(Of )).MakeGenericType(query.ElementType), query), IList)
End Function


Joe

PS - Aaron and I just fixed the latest version of Csla for the LinqBindingList to be able to sort multiple columns using MS Dynamic Query. Not sure if it is checked in yet though. All Editable Child Collections return LBLs so the code for them is slightly different.

PPS - the forum does not allow angle brackets around the word Extension above so the attribute code is not quite correct!

RockfordLhotka replied on Friday, March 27, 2009

Joe, you should check to see if it is in the version 3.6.2 release candidate
(www.lhotka.net/cslanet/download.aspx) because that's the version that'll be
released on Monday or Tuesday (barring anyone raising a big alert).

Rocky


-----Original Message-----
From: JoeFallon1 [mailto:cslanet@lhotka.net]
Sent: Friday, March 27, 2009 8:58 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: RE: Dynamic Sorting, ReadOnlyListBase and
LINQ

Dynamic LINQ code like this works on ReadOnlyLists:

Private mSortedList As System.Linq.IQueryable

mSortedList = mList.AsQueryable.OrderBy(mSortExp & " " &
mSortDirection.ToString)

dataGrid.DataSource = mSortedList.ToList

For Some reason the MS Dynamic Query Library is missing the ToList
extension. So I added this to my copy:

'JF - 1/5/09 added this extension:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2666544&SiteID=1#26701
01
_
Public Function ToList(ByVal query As IQueryable) As IList
Return DirectCast(Activator.CreateInstance(GetType(List(Of
)).MakeGenericType(query.ElementType), query), IList)
End Function


Joe

PS - Aaron and I just fixed the latest version of Csla for the
LinqBindingList to be able to sort multiple columns using MS Dynamic Query.
Not sure if it is checked in yet though. All Editable Child Collections
return LBLs so the code for them is slightly different.

JoeFallon1 replied on Friday, March 27, 2009

RockfordLhotka:
Joe, you should check to see if it is in the version 3.6.2 release candidate
(www.lhotka.net/cslanet/download.aspx) because that's the version that'll be
released on Monday or Tuesday (barring anyone raising a big alert).

Rocky


I just checked - it is not there.
I sent it to you and Aaron a while back. Aaron wanted to run some unit tests on it last weekend. I have not heard anything about that though.
Joe

setiabud replied on Sunday, March 29, 2009

It looks like in the 3.6.2 release notes there is a note about Dynamic LINQ to BusinessListBase. Is that what you meant, Rocky - that the bug is suppose to be fixed in 3.6.2? I am still using 3.5 right now.

For Joe: That ToList extension method you noted is just for ReadOnlyList, correct? Because my ReadOnlyList sorting with Dynamic LINQ works perfectly right now. It is just when I am trying to sort a BusinessListBase that somehow getting back an empty back.



Joe

RockfordLhotka replied on Sunday, March 29, 2009

Several changes/fixes around LINQ to CSLA are in 3.6.2. Unfortunately the
support for Dynamic LINQ in 3.6.2 doesn't completely work. Hopefully the
issues can be resolved for 3.6.3.

Rocky

JoeFallon1 replied on Monday, March 30, 2009

setiabud:
It looks like in the 3.6.2 release notes there is a note about Dynamic LINQ to BusinessListBase. Is that what you meant, Rocky - that the bug is suppose to be fixed in 3.6.2? I am still using 3.5 right now.

For Joe: That ToList extension method you noted is just for ReadOnlyList, correct? Because my ReadOnlyList sorting with Dynamic LINQ works perfectly right now. It is just when I am trying to sort a BusinessListBase that somehow getting back an empty back.



Joe


Your sorting works perfectly right now because you are doing a single column sort. Maybe 2 columns. It will fail on 3 or more. That is the fix we are adding to Dynamic Linq.

ToList is used for ReadOnly Lists as an optional feature. If you do not use it but bind the list to a grid directly then you need to set additional grid properties (to tell it the number of items I think).

Joe

Copyright (c) Marimer LLC