Practical example of paging and sorting

Practical example of paging and sorting

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


kdog posted on Wednesday, March 21, 2007

I read the 2.1 handbook and now I am trying to setup paging and sorting in my readonlylistbase class but I must admit my brain is not processing the 2.1 handbook code all that well.

Does anyone have a real world example that I could look at?

Or is there an updated ProjectTracker download for this that I am missing?

 

kids_pro replied on Wednesday, March 21, 2007

This is how I succesfully get paging work with CSLA:
    // class declaration implement Csla.Core.IReportTotalRowCount

    [Serializable()]
    public class ContractorList :
        Csla.ReadOnlyListBase<ContractorList, ContractorInfo>,
        Csla.Core.IReportTotalRowCount

    // later on the DataPortal_Fetch()
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = "SELECT_WITH_PAGING";// you be able to find this store proc on google.

    int currentPage = 1 + criteria.SelectArgs.StartRowIndex / criteria.SelectArgs.MaximumRows;

    cmd.Parameters.AddWithValue("@strFields", "*");
    cmd.Parameters.AddWithValue("@strPK", "ContractorID");
    cmd.Parameters.AddWithValue("@strTables", "Contractor");
    cmd.Parameters.AddWithValue("@intPageNo", currentPage );
    cmd.Parameters.AddWithValue("@intPageSize", criteria.SelectArgs.MaximumRows);
    cmd.Parameters.AddWithValue("@blnGetRecordCount", 1);
   
   //cmd.Parameters.AddWithValue("@strFilter", "");
   cmd.Parameters.AddWithValue("@strSort", "ContractorID ASC"); // it is very important to specify the sorting base on unique column otherwise you paging will get mess up.

    using (SafeDataReader dr = new SafeDataReader(cmd.ExecuteReader())) {
        // Get records
        RaiseListChangedEvents = false;
        this.IsReadOnly = false;
        while (dr.Read())
            this.Add(ContractorInfo.GetContractorInfo(dr));

        this.IsReadOnly = true;
        RaiseListChangedEvents = true;

        // get total row count
        if (criteria.SelectArgs.RetrieveTotalRowCount) {
            dr.NextResult();
            dr.Read();
            _totalRowCount = dr.GetInt32("RECORDCOUNT");
        }
    }

Hope this would help.

kdog replied on Thursday, March 22, 2007

Thanks for the sample.  It helps a bit in seeing what another is doing.....

However, I am in a situation where I do not have control over the Stored Proc.  The vendor is writing the Stored Procs as the system we are writing is interfacing with a vendor product on an iSeries DB2 system. 

Currently, the SP is giving me back the entire list results based on the criteria given.  So I was trying to figure out how to retrieve all the records using the Proc in the fetch but on subsequent calls essentially change the rows returned based on the page and not recall the SP.

Any ideas out there or samples like this?

 

 

 

kdog replied on Thursday, March 22, 2007

hmm.... i got paging to work by just setting the gridview to page and then i removed all my code in my class to implement the IReportTotalRowCount.

Now sorting.... Oy...

Now I am confused as to when to use IReportTotalRowCount interface...

RockfordLhotka replied on Friday, March 23, 2007

ASP.NET allows paging to occur at virtually any level.

The grid control can do it by itself, though that's the least efficient technique, because the data has to be loaded into the web server's memory, and the grid just grabs the page it wants - ignoring most of the data you've loaded.

Or your data source can do it - I could have made CslaDataSource itself do paging for example. I opted not to - but rather to defer it to you.

But that means YOU can do the paging in several places, including in the SelectObject event handler, in your object's factory method, in your DataPortal_Fetch() method or in a stored procedure.

In any of those four scenarios, data binding (and CslaDataSource) provide you with the index of the first desired row and the page size. The rest is up to you at that point.

If you allow the grid to do all the work, and performance is acceptible, then have at it. You don't need to do any work at all.

But if perf becomes an issue, then you need to set the property on CslaDataSource to indicate you support paging, and you need to implement IReportTotalRowCount and implement paging in one of those four locations.

RockfordLhotka replied on Friday, March 23, 2007

I guess I should say this too.

If you don't have control over the sproc, then you really have no choice but to get all the data from the database... You'll just ignore most of what you got.

So my suggestion is to do the paging in your DP_Fetch() method. Call the sproc, and get all the data. That'll give you the total row count for IReportTotalRowCount interface. Then you can put only the requested rows into your collection - totally ignoring the rest of the rows of data from the db.

So if you were asked to get 10 rows starting at index 100, you'd read 99 rows from the db and discard them. Then you'd read the next 10 rows and add them to your collection. And then you'd read and discard the remaining rows to get your total row count for IReportTotalRowCount.

Your collection object would then contain just those 10 rows and the total row count - because that's all that data binding wants or needs anyway.

kdog replied on Friday, March 23, 2007

Rocky,

As usual I appreciate the clarification. :)  The vendor is extremely worried that the iSeries DB is going to have performance issues so they would like as few calls to the DB as possible.  For the moment, I am letting the gridview page instead of making several calls to the DB.

For my first test I have setup a page that returns 33 records.  I have the grid do all the paging and I do the sorting in the SelectObject since I have at this time no way to control changing the sort returned to me from the vendor SP.

You got me thinking on this however.... I used the sessioned object for the sorting. I could do the same for paging.  Perhaps this will give another performance increase..... 

I may have to look at convincing the vendor to give a paged SP and then we can at least test to see which one is better on performance under serious load.

I am curious as to how to run some perf tests on this?  In VS2K3 I would have used app test center but now it is gone (I am using VS2K5 Pro). 

Anybody know of good free tools to run perf tests on my app?

mongo replied on Saturday, April 14, 2007

Check out my post over here:  http://forums.lhotka.net/forums/thread/13802.aspx

This allows you to take any in-memory set of objects and auto-sort/page.  It seems to fit what you're asking for and minimizes the amount of code you need to write.  It's also a generic class so it can fit differing grids.

fabiousa7 replied on Thursday, January 24, 2008

.

fabiousa7 replied on Thursday, January 24, 2008

kids_pro:
This is how I succesfully get paging work with CSLA:
    // class declaration implement Csla.Core.IReportTotalRowCount

    [Serializable()]
    public class ContractorList :
        Csla.ReadOnlyListBase<ContractorList, ContractorInfo>,
        Csla.Core.IReportTotalRowCount

    // later on the DataPortal_Fetch()
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = "SELECT_WITH_PAGING";// you be able to find this store proc on google.

    int currentPage = 1 + criteria.SelectArgs.StartRowIndex / criteria.SelectArgs.MaximumRows;

    cmd.Parameters.AddWithValue("@strFields", "*");
    cmd.Parameters.AddWithValue("@strPK", "ContractorID");
    cmd.Parameters.AddWithValue("@strTables", "Contractor");
    cmd.Parameters.AddWithValue("@intPageNo", currentPage );
    cmd.Parameters.AddWithValue("@intPageSize", criteria.SelectArgs.MaximumRows);
    cmd.Parameters.AddWithValue("@blnGetRecordCount", 1);
   
   //cmd.Parameters.AddWithValue("@strFilter", "");
   cmd.Parameters.AddWithValue("@strSort", "ContractorID ASC"); // it is very important to specify the sorting base on unique column otherwise you paging will get mess up.

    using (SafeDataReader dr = new SafeDataReader(cmd.ExecuteReader())) {
        // Get records
        RaiseListChangedEvents = false;
        this.IsReadOnly = false;
        while (dr.Read())
            this.Add(ContractorInfo.GetContractorInfo(dr));

        this.IsReadOnly = true;
        RaiseListChangedEvents = true;

        // get total row count
        if (criteria.SelectArgs.RetrieveTotalRowCount) {
            dr.NextResult();
            dr.Read();
            _totalRowCount = dr.GetInt32("RECORDCOUNT");
        }
    }

Hope this would help.

I am doing a very similar implementation for my server paged and sorted objects.

But my stored procedure became very complex and cumbersome, would you share how you implemented your stored procedures?

Im specially interested in the "@strSort" portion of it.

Thanks,

Fabio

RobKraft replied on Friday, January 25, 2008

Fabio, here is a link to an example stored proc for paging and sorting I wrote last year.

http://robkraft.spaces.live.com/blog/cns!E6687F3AB6372637!142.entry

This is designed to work with SQL Server 2000 or SQL Server 2005.  If you only support SQL 2005, then take a look at the original post I reference in my blog.  It shows the simpler way to support paging using SQL 2005.

dantruj replied on Tuesday, January 29, 2008

As stated earlier there are 4 places for paging to be implemented.  Currently I am doing filtering then sorting in the

protected void ContactsListDataSource_SelectObject(object sender, Csla.Web.SelectObjectArgs e)

So here are my questions:

If I do paging in the SelectObject event, do I need to implement the IReportTotalCount interface in my List object?

Since I do filtering and sorting in the SelectObject event, am I forced to do paging there as well instead of doing it in DP_Fetch?

I mean if I have 20 contact records that are populated each time I fill my List (ReadonlyListbase), and 5 of them have last names that start with 'A', but they are not in order in the table, I would want to filter them first before paging.  Because paging would pull the first 10 records thus excluding some of the contact records that have lastnames that begin with 'A'.  Is this correct?

 

 

 

Copyright (c) Marimer LLC