How to unit test a grid with paging - asp.net

A common web UI design is to display a sortable grid (GridView, ListView, DataGrid) with paging. That is, the user can click on any column header to cause the records to be sorted in ascending or descending order on that column's data. And, the user can navigate among the pages of, say, 10 records at a time.
There may be millions of database
records that could potentially be
displayed on the grid.
There are many possible filters that
could be applied to the data
selection. The displayed records
might apply to the current user, or
to a date range, or to a customer,
department, product, order.
The user can sort the displayed
records on any column, and they can
navigate among pages.
How would you write a unit test(s) to confirm that the selected records are the correct records, for this filter, this page, and this sort order?

You will have to
decouple the filtering, sorting from the actual source so that you can mock the datasource
and test if the logic returns the correct records.
decouple the paging logic from the grid so that you can test if the paging gives the right indexes back.
That way you can test the filtering and the paging logic in separate units.
Next you could also use a automatic webtest to test the complete stuff (integration test).

Related

How to develop a "Check All" feature on a large, paginated grid/table

I am looking for advice on best practices regarding the following scenario.
I have a grid that supports server-side pagination.
Let's say that there are 100,000 records in the grid, and each page size is 100 records.
Let's say they "Select All".
Considering the records are paginated, do you store a list of "selected" records client-side or server-side?
My first pass was to have the service page that populates the grid to return a comma delimited list of all the records primary keys for future reference alongside the normal dataset, but this seems clunky or even dangerous with large datasets.
My second pass was to store all the records in a special table for future reference, but this adds a lot of overhead in the form of table management to the process.
Or something else? Thanks!

Circumventing query page size limitations

In the Project Tracker template there is a feature where statistics for a certain project's items are displayed. You can filter the project items, but the statistics will only show those statistics for all the project items, i.e. the filters do not affect the statistics.
I would like to add the feature of filters affecting those statistics in a similar implementation of mine. My current solution passes the keys of those project items (affected by filters, too) to a calculated data source, which then calculates the statistics using those item keys, essentially applying the filters used in the page.
My issue is that my calculations are restricted by the query page size. For example, if I apply filters that limit the number of items to 15 records, but the page size is 10 records, I will only have statistics of those first 10 items, which is not useful. I'd need to have the statistics on all the records that are left after filtering.
One way to solve this would be to get rid of the query page size and leave it at 0. However, similarly to the Project Tracker template, I'm displaying the project items on the page in a table, and if I do that, the page becomes too heavy.
How can I circumvent the query page size? I'm thinking I could
limit the items displayed in the page by some other way than query page size (i.e. hiding items from the UI)
use a different datasource for the statistics, but in some way copying the filters used in the datasource that is displaying the project items
Both of these ways I could think of, I can't seem to implement. I don't know how I could hide items from the UI to make it less heavy, as query page size pretty much does it. I have also tried copying the filters from a datasource to a similar one, but that does not seem to work.
EDIT: I might have come up with a way to solve this myself, but I still need to implement it. Now I'm using the page size restricted Items Ds to apply the filters on, and the statistics are build from this data source. If instead, I use a non-restricted Ds called AllItems, and apply the filters on it, and then pass the item keys to a page size restricted Ds (to show the items in UI) AND to a calculated Ds (for the stats). Will make a response once I've verified it works.
I solved the issue myself.
To produce (refreshable) statistics subject to filtering but not restricted by page size, I used the following datasource structure:
In this structure, the filters practically flow to the data sources below, as they are passed the ItemKeys that fit the filter. What this completes is that my Statistics (used in piegraphs etc.) can be filtered dynamically and account for all the records that fit the filter, while the UI does not get crowded over too many records, as the data source used in UI has a query page size limitation.

Display Paging In ASP.NET GridView Even with a single Page

In My Database I Have 10000000 Records. In GridView First I Am Showing First 10 Records. In Order To See the Next Records User Need to Click Page Numbers ( 1,2,3,------10000). But As I'm Retrieving 10 Records for The First Time GridView Paging is not Showing.
Is There Any Way To Show Paging In ASP.NET GridView Statically ?
For so many records, I won't recommend Paging. You can show Top 20 recently added records and provide options to filter out records. A user can enter keywords. ReQuery and ReBind the GridView with this new result set.
You might also consider using PetaPoco, a Micro-ORM, which will help you fetch paged result.
With so many records, you really need to take into account the exact queries being run to pull back the data.
There are numerous ways of doing data paging ( http://beyondrelational.com/modules/2/blogs/28/posts/10434/sql-server-server-side-paging-with-rownumber-function.aspx ). However, the "best" way is dependent on the exact version of SQL Server you are running.
Essentially, the solutions boil down to you passing a page number and number of records per page through some type of query. Usually a stored procedure as the query can be quite messy.
Once there, you have an option. Either send the total record count back as an OUT parameter in your query and the result set back normally, or you send the total record count back as a column. There are definitely efficiency concerns with both options as one way requires the query to be run twice and the other requires an extra column of data which increases network traffic.
Once you have that solved then you can figure out exactly how you want the UI to work.

About the GridView control in asp.net

I'm working on a web application, on one page I am inserting records in the database and I want to display the data in a GridView but on a diffrent page. How can I do this?
I know how to display records in a GridView, but I want to know if there are two web pages,
on one page provides the facility to insert the records and U want to display the records in the GridView bit on the second page.
While it is possible to retain the data being inserted without retrieving it from the database, I think it is better to save the data on the first page and retrieve it from the database on the second page.
You can do this by writing inline SQL or a stored procedure. One simple approach would be to pass the resultset into a DataTable and bind a GridView to that.
That does involve more work -- more code and more trips to the database. However, I think it is very useful when performing INSERTs that the web page is updated to display what actually got into the database. Sometimes, this is different from what the user thinks they entered, and they can see the problem immediately.
One question would be how to identify the data that has just been inserted. I can think of several ways to do that. One is to query for all records entered today by the person logged in (which is recorded in the CreatedBy and CreatedDate columns of the database tables). Sort the resultset in descending order of CreatedDate, so that the most recent entries appear at the top of the GridView. Another would be by assigning a batch number to the data entry and retrieving only the data in that batch.
If you really want to hang on to the data entry, you could put it into Session on the first page, and then retrieve it from Session for display on the second page.
Following along the lines of what DOK said, it's also a lot easier to validate data entered by your users in your business logic before you submit it to the database.
Secondly, users can change their minds about data on a webpage frequently. The data on the web could be in an partially-finished state or could have typos or errors in it. If someone else saw this data and believed that it needed to be completed, then you could end up with duplicated entries in the database that would then require reconciliation.
Honestly, your best bet is to use the Session object to hold temporary user data. The MSDN entry for the GridView RowEditing event contains some great source code for this approach. Whenever I have to use GridViews to handle data from the database, I mimic this.
In addition to handling problems with temporary data storage, you can compare the Session object to your database results to determine whether or not new rows have been inserted. This is somewhat costly as it involves overloading the Equals method (and GetHashCode as well, if you follow what Microsoft recommends) and using Equals to iterate over the two collections, comparing the properties of both objects, and determining which records are new based on records that don't exist in your Session object, but do exist in your database object.
It's also worth noting that this approach assumes that you don't delete data from your database, but set the status of a record in your database to "Deleted" -- if that's a boolean field or an sequence of codes you use to describe the state of rows in a table.

MS Reportviewer - Save Expanded/Collapsed Nodes in ViewState?

I have a report that's being populated from an ObjectDataSource. The report includes expandable/collapsible nodes per user.
I'm allowing the viewer to filter the report by setting the FilterExpression on the datasource, then calling ReportViewer1.LocalReport.Refresh(). This is done during PostBack.
This filters the results, but the state of the expanded/collapsed nodes is lost. Is there some way to store the expanded/collapsed nodes in the ViewState? Or is there a better way to accomplish this altogether?
I know its been a while since this question was asked, but since i had to go through this recently i want to share my experience with somebody who might be dealing with this.
It's tricky but if you add a multivalued parameter to your report and the values match the values in the toggable fields, then you can write a group expression in the grid (And in the labels so those go away too). Once that is done, you just have to keep track of what is toggled (this is hard, but is possible with javascript).
Basically, there are two of the hidden child controls in the reportviewer control (indexes 4 & 5 in vs2008) that have the name of the event and the id of the table cell clicked, with this you cand build an array in javascript and keep track of the status of all toggable fields.

Resources