Practical ASP.NET

Dynamic Data Retrieval

You can't always make all of your data retrieval decisions at design time -- sometimes you have to wait for the user to tell you what data to get. Peter shows you how to work with a DataSource to retrieve data dynamically at runtime.

One of my clients gave me a reporting page from Hell: The user would be able to select the database they were drawing data from, the fields that would be displayed and the criteria for selecting records. Normally, in using the ASP.NET DataSources, I can configure the DataSource and, at runtime, just pick up a few parameters from controls on the page. With my client's page, however, I would have to pick up all the settings at runtime.

My first step, as usual, was to put a DataView and a DataSource on the page. But then I deviated from my usual practice: I didn't configure either control. I didn't even attach the DataView to the DataSource.

When a page is first displayed to the user, if a DataView is connected to a DataSource, ASP.NET automatically retrieves the data for the DataView. For this page, however, I don't want the data to be retrieved until the user requests it, so I don't connect the DataView to the DataSource. (For more on deferring retrieval until the user requests it, see http://visualstudiomagazine.com/articles/2008/07/30/deferring-data-retrieval-in-masterdetail-pages.aspx.)

Selecting the Database
To control data access at runtime, I just set properties on the DataSource. The overall process is similar for both the ObjectDataSource and the SqlDataSource, but differs in the details.

For instance, with the SqlDataSource I let the user pick which database to draw from by setting the ConnectionString on the DataSource. This example assumes that there's a RadioButtonList of databases that the user can select from:

Me.SqlDataSource1.ConnectionString = ConfigurationManager. _
ConnectionStrings(Select Case Me.rdbDatabases.SelectedValue()). _
ConnectionString

On the ObjectDataSource, you let the user select where the data comes from by choosing the right factory class. You specify the factory class by setting the TypeName property to the full name of the class. This example assumes the existence of a RadioButtonList that lets the user select a factory class:

Me.ObjectDataSource1.TypeName =  Me.rdbMethods.SelectedValue() 

Picking Fields
Back to the SqlDataSource: To let the user choose which fields to retrieve, you set the SqlDataSource's SelectCommand property to a SQL statement or the name of a stored procedure. The following code assumes that the user can select multiple items from a CheckBoxList of field names. This code loops through the ListItems in the CheckBoxList, adding the fieldnames for whatever ListItems are marked as Selected:

Dim sbFields As New System.Text.StringBuilder()
For Each li As ListItem In Me.chkFields.Items
If li.Selected = True Then
sbFields.Append(li.SelectedValue & ", ")
Next
sbSQL.Remove(sbSQL.Length-2, 2)
Me.SqlDataSource1.SelectCommand = _
"Select " & sbFields.ToString() & " From Employees"

Before I get critiqued for concatenating values into SQL statements, let me say two things. First, the prohibition against concatenating SQL statements is a prohibition against using "user-entered values," which may include text that implements a SQL injection attack. I'm not doing that: I'm concatenating in my own values from my own CheckBoxList. Second, you're perfectly free to let the user select between names of stored procedures or between predefined lists of fields rather than require the user to select individual fields, as I do here. If you do use a stored procedure, make sure that you set the DataSource's SelectCommandType property to the StoredProcedure enum value:

Me.SqlDataSource1.SelectCommandType =  _
SqlDataSourceCommandType.StoredProcedure

With the ObjectDataSource, to control the data retrieved you just set the ObjectDataSource's SelectMethod to the name of the method being used. This example assumes the existence of yet another RadioButtonList to let the user select the method to use:

Me.ObjectDataSource1.SelectMethod = Me.rdbMethods.SelectedValue() 

Timing
The question now is when you should make these changes. The answer is: At the last possible moment.

For my "page from hell", I put a button on the page that lets the user retrieve data. In the Click event for the button, I connect the DataView to the DataSource by setting the DataView's DataSourceId to the Id of the DataView. I then call the DataView's DataBind method to fetch the data:

Me.MyDataView.DataSourceId = Me.MyDataSource.Id
Me.MyDataView.DataBind()

When you call the DataBind method of a DataView, the DataView reaches over to the DataSource and calls the DataSource's Select method. This, in turn, causes the DataSource to fire its Selecting event just before retrieving the data. It's in that event that you should set the properties I've shown above.

However, I have one more issue to address. It will be an unusual SQL statement and a very unusual stored procedure or method that doesn't require parameters. But I'll discuss that in next week's column.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Hands On: New VS Code Insiders Build Creates Web Page from Image in Seconds

    New Vision support with GitHub Copilot in the latest Visual Studio Code Insiders build takes a user-supplied mockup image and creates a web page from it in seconds, handling all the HTML and CSS.

  • Naive Bayes Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the naive Bayes regression technique, where the goal is to predict a single numeric value. Compared to other machine learning regression techniques, naive Bayes regression is usually less accurate, but is simple, easy to implement and customize, works on both large and small datasets, is highly interpretable, and doesn't require tuning any hyperparameters.

  • VS Code Copilot Previews New GPT-4o AI Code Completion Model

    The 4o upgrade includes additional training on more than 275,000 high-quality public repositories in over 30 popular programming languages, said Microsoft-owned GitHub, which created the original "AI pair programmer" years ago.

  • Microsoft's Rust Embrace Continues with Azure SDK Beta

    "Rust's strong type system and ownership model help prevent common programming errors such as null pointer dereferencing and buffer overflows, leading to more secure and stable code."

  • Xcode IDE from Microsoft Archrival Apple Gets Copilot AI

    Just after expanding the reach of its Copilot AI coding assistant to the open-source Eclipse IDE, Microsoft showcased how it's going even further, providing details about a preview version for the Xcode IDE from archrival Apple.

Subscribe on YouTube

Upcoming Training Events