LLBLGenDataSource2 and Sorting

Posts   
1  /  2  /  3
 
    
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 13-May-2006 16:33:07   

When using Sorting on a GridView bound to a LLBLGenDataSource2 with LivePersistence disabled I've noticed a couple of things.

Firstly, the SortExpression property on the GridView appears to be case sensitive. Eg If I have a property on my entity called "Surname" then using SortExpression="surname" will not work, it has to be SortExpression="Surname".

When using the ObjectDataSource this is not case sensitive. Is this by design?

Secondly, when the SortExpression is composed of multiple fields (eg SortExpression="Surname, Forename") then the OrderBy clause in the SQL seems to be generated incorrectly when sorting in Descending order, eg:


ORDER BY [dbo].[Students].[Surname] ASC, [dbo].[Students].[Forename] DESC

I believe this should be:


ORDER BY [dbo].[Students].[Surname] DESC, [dbo].[Students].[Forename] DESC

When sorting in Ascending order, the OrderBy clause is generated correctly.

Jez

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 14-May-2006 11:45:10   

They pass an ASCII string with the names and sort operators to the datasourcecontrol. Yes, an ascii string with the operators already in place. frowning .

I have it case-sensitive now, I can make it case-insensitive, which might be more flexible. I'll check if they pass the sort operators correctly. I have the feeling they pass ColA, ColB OPERATOR and operator then works for both the columns, but I'm not sure.

This is one of the many things that's undocumented in their code.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 16-May-2006 16:22:47   

Jez wrote:

When using Sorting on a GridView bound to a LLBLGenDataSource2 with LivePersistence disabled I've noticed a couple of things.

Firstly, the SortExpression property on the GridView appears to be case sensitive. Eg If I have a property on my entity called "Surname" then using SortExpression="surname" will not work, it has to be SortExpression="Surname".

When using the ObjectDataSource this is not case sensitive. Is this by design?

Secondly, when the SortExpression is composed of multiple fields (eg SortExpression="Surname, Forename") then the OrderBy clause in the SQL seems to be generated incorrectly when sorting in Descending order, eg:


ORDER BY [dbo].[Students].[Surname] ASC, [dbo].[Students].[Forename] DESC

I believe this should be:


ORDER BY [dbo].[Students].[Surname] DESC, [dbo].[Students].[Forename] DESC

When sorting in Ascending order, the OrderBy clause is generated correctly.

It's case insensitive for the ObjectDataSource as it sorts using a dataview object: it simply plugs the sortexpression as the sort string of the dataview. The problem is: they pass the sortexpression of the column you clicked to the control and append DESC to the expression when it's descending sort but don't append anything if it's an ascending sort.

Now, as you can imagine this is a pretty sucky way of doing it. I mean: why not pass a Dictionary<string, ListSortDirection> ? It's .net 2.0 after all. Because if you sort on 2 columns, say Col1 and Col2, and one has to be ascending and the other descending, what will the string be? Col1, Col2 DESC.

So the datasource control can't figure out which column to apply the DESC to: both or just the last one.

I.o.w.: not solvable.

I've added a case insensitive comparer to the dictionary of field names which is passed to the routine which creates the SortExpression object, so the fieldnames can now be case insensitive. For filters, names have to be case sensitive.

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 17-May-2006 10:14:26   

Thanks for looking into the above issues.

Today I encountered another problem with GridView sorting. I have a GridView bound to an LLBLGenProDataSource2 (with livepersistence disabled). When this datasource is bound to a Typed View (rather than an EntityCollection) I receive the following message when sorting the gridview:

Object reference not set to an instance of an object.

Stack trace:


at SD.LLBLGen.Pro.ORMSupportClasses.LLBLGenProDataSourceViewBase.ProduceSortExpressionFromString(IEntityFields2 fields, String sortargument)
   at SD.LLBLGen.Pro.ORMSupportClasses.LLBLGenProDataSourceView2.ProduceSorterToUse(IEntityFields2 fields, DataSourceSelectArguments arguments)
   at SD.LLBLGen.Pro.ORMSupportClasses.LLBLGenProDataSourceView2.ExecuteSelectTypedView(Int32 pageSize, Int32 pageNumber, DataSourceSelectArguments arguments)
   at SD.LLBLGen.Pro.ORMSupportClasses.LLBLGenProDataSourceView2.ExecuteSelect(DataSourceSelectArguments arguments)
   at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback)
   at System.Web.UI.WebControls.DataBoundControl.PerformSelect()
   at System.Web.UI.WebControls.BaseDataBoundControl.DataBind()
   at System.Web.UI.WebControls.GridView.DataBind()
   at System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound()
   at System.Web.UI.WebControls.GridView.OnPreRender(EventArgs e)
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 17-May-2006 10:43:20   

You use the very latest runtimes?

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 17-May-2006 10:45:56   

Yes

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 17-May-2006 11:27:55   

Huh...


/// <summary>
/// Produces the sort expression from a string expression provided by ASP.NET
/// </summary>
/// <param name="fields">The fields.</param>
/// <param name="sortargument">The sortargument.</param>
/// <returns></returns>
protected ISortExpression ProduceSortExpressionFromString( IEntityFields2 fields, string sortargument )
{
    Dictionary<string, IEntityFieldCore> fieldsList = new Dictionary<string, IEntityFieldCore>( fields.Count, StringComparer.InvariantCultureIgnoreCase );
    foreach( IEntityField2 field in fields )
    {
        fieldsList.Add( field.Alias, field );
    }

    return ProduceSortExpressionFromString( fieldsList, sortargument );
}

Either fields is null, or the new operator fails... Following the trail, it's only possible if the view doesn't have any fields, but even then... If you open the form in the asp.net designer, does it show proper datasourcecontrols or an error sign on it? (which signals outdated dlls).

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 17-May-2006 11:44:31   

Hi Frans,

There are no errors when opening the form in the designer. I will re-download the latest beta and copy the runtime libraries into my Bin folder again. The exception seems to occur when calling the GetFieldsInfo() method on the typed view.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 17-May-2006 11:57:26   

REproduced. It's something with the fields object. I can't fetch any data using the fields object either... Looking into it.

Hmm. it fetches data correctly, but I see just the headers, no rows...

Edit: ok I'm removing foot from mouth now, it was me who was stupid (as always). rows now show up. When I page to the next page, I get the same error. The fields object of the typedview is gone.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 17-May-2006 12:21:27   

It's caused by a bug in the TypedView class. When it's serialized, the _fields object isn't serialized into the data. So when it's deserialized, the _fields object inside the typedview is null, as it's not re-created.

To work around it for now: set the CacheLocation to session instead of the default: viewstate.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 17-May-2006 13:52:19   

Fixed in next build simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 17-May-2006 13:55:57   

Brilliant, thanks simple_smile

Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 18-May-2006 16:59:52   

Hi Frans,

I bet you're tired of me reporting bugs with gridviews/sorting, but here's another one wink

When you click on a gridview heading to sort by that field, if the field is a 'field on a related field' then the e.Sorter does not contain a sortclause when PerformSelect is fired (e.Sorter.count is always 0).

Jez

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 18-May-2006 17:59:01   

Jez wrote:

Hi Frans,

I bet you're tired of me reporting bugs with gridviews/sorting, but here's another one wink

No not at all, please keep them coming simple_smile

When you click on a gridview heading to sort by that field, if the field is a 'field on a related field' then the e.Sorter does not contain a sortclause when PerformSelect is fired (e.Sorter.count is always 0).

Jez

Clearly a bug, I think in the category "oops, forgot to add that".

It's still problematic though. The field isn't found in the entity fields, so the sortclause isn't produced. The field can be a field mapped onto a related field, OR it can be a property added manually to the entity. So creating sortexpressions for these fields is problematic if even possible.

The sorting therefore will be clientside for these fields.

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 18-May-2006 18:08:39   

Thanks for the response. I had a suspicion that server side sorting would be difficult with custom properties/fields on related fields.

How were you planning on implementing this? At the moment I pass the e.Sorter to a custom method that runs the query. When you say the sorting will be clientside do you mean that the datasource will take care of the sorting itself or will I still need to pass some form of sortclause to my method (in most situations I use the datasource with livepersistence disabled)

Thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 19-May-2006 08:35:38   

It will create a SortExpression for properties to do client-side sorting on the defaultview it returns to the bound control simple_smile So it's little work: it simply does the sorting after the fetch.

Livepersistence or not, that's not important: in both cases hte sortexpression is created inside the datasourcecontrol.

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 19-May-2006 11:20:49   

Thanks for clearing that up.

As a suggestion, would it be possible to optionally apply this behaviour to all sorting through a property on the datasource? (eg something like EnableClientSorting). For example, if this was enabled then all fields would be sorted client side without the need to deal with passing the e.Sorter. I realise this could impact performance but I could forsee some situations where this could be useful.

Also, on a slightly unrelated issue, would it be possible to make the PerformSelect event the 'default' event for the DataSource controls so that when you double click them in the designer it automatically adds the handler code in the codebehind file. I believe this can be achieved by decorating the method with the [DefaultEvent()] attribute.

Thanks simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 19-May-2006 21:18:31   

Thanks, I'll look into making these changes simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 23-May-2006 16:39:09   

The next build will have a SortingMode property. This property controls if the sorting takes place on the server (ServerSide, default) or client (ClientSide). If client, it will sort on all properties specified by the bound control by sorting the default entity view which is returned. Otherwise it will only sort on the entityfields which are part of the entity's target: table or view.

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 23-May-2006 17:49:02   

Excellent simple_smile

These data source controls are saving me a heck of a lot of work smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 23-May-2006 18:08:09   

Jez wrote:

Excellent simple_smile

These data source controls are saving me a heck of a lot of work smile

I'm glad you like them. simple_smile Working with them some more I indeed see the advantages of them simple_smile I made a form with 1 line of code and: - a dropdown box with customers which filters: - a grid with the orders of the selected customer and of which I could select a row of

and I also had a formview with the order fields so I could edit the selected order or add new ones. The one line of code was required to set the pageindex of the formview so I could use 1 datasource wink .

The new beta is available, with the sort option simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 23-May-2006 18:46:46   

I just tried it out and its working great. I also noticed you set PerformSelect to be the default event - thanks for that simple_smile

Something else that occurred to me was that when using the ObjectDataSource there are a number of situations where I use the DataSource.Selecting() event to add extra parameters to the SelectParameters collection at runtime. How feasible would it be to have something similar on the LLBLGenProDataSource(2) controls when using LivePersistence=true?

Edit: Spoke too soon, I think I found a bug. When clicking on a heading to perform a sort, if paging is enabled the grid will always return to page 1.

Edit2: My previous edit is probably nothing to worry about actually as this behaviour is also apparent with the objectdatasource. Must be a 'feature'. wink

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 23-May-2006 20:14:42   

Server-side sorting and paging indeed reverts to page 1 simple_smile

Selecting() is there in teh ObjectDataSource because it doesn't have a livepersistence is false option. I think it would be of no use to add an event which requires code in the code behind anyway. Or do you disagree? simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 23-May-2006 20:48:30   

I agree that in most situations there would be no need to write code behind when using livepersistence=true. However, there are some situations where I think it could be useful.

For example, in one of our applications we have a static session manager class called WebCore.Current. One of the static properties in this is "User" which returns a UserEntity out of the Session object. With the ObjectDataSource I could do something like:

void dsSelecting(object sender, ObjetDataSourceSelectingEventArgs e)
{
    if(!e.InputParameters.Contains("Surname"))
    {
        e.InputParameters.Add(WebCore.Current.User.Surname);
    }
}

If the LLBLGenProDataSource had something similar then I wouldn't need to write any code in the PerformSelect handler (as the livepersistence would take care of that) but there's still a flexible way to add parameters.

Maybe I'm just being lazy stuck_out_tongue_winking_eye

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39951
Joined: 17-Aug-2003
# Posted on: 23-May-2006 21:17:02   

Though why not add the insertparameter at design time? simple_smile Or is that not possible due to the source of the parameter which isn't known?

Frans Bouma | Lead developer LLBLGen Pro
1  /  2  /  3