Chapter 16. Using the QueryExtender Control

One of ASP.NET’s great strengths is the near infinite number of ways in which you can populate your pages with data. Although there have always been low-level options available such as ADO.NET, in recent years it has become more popular to use Object-Relational Mapping (ORM) tools, dynamic data tools, and other abstractions. Most of these abstractions work either at the code-behind level or within other Assemblies.

This chapter introduces you to the QueryExtender control that enables you to modify standard ASP.NET declarative data sources with rich filtering and sorting functionality. This enables the developer to build rich, dynamic, data-driven pages and maintain all the data sorting and filtering logic completely within the ASPx markup without dropping to the code-behind level.

Introduction to the QueryExtender Control

When you retrieve data through a data source control, you traditionally sacrifice the fine-grained control over the query in exchange for the declarative (often design-surface friendly) simplicity of the data source control. The QueryExtender control aims to give you back some of that control while still giving you all the benefits of a declarative data source.

The QueryExtender control gives you the ability to specify filter criteria, sorting options, and even custom queries written in LINQ all in a declarative fashion using a suite of nested child controls that derive from the ParameterDataSourceExpression class. The next section of this chapter provides an overview of the various types of filtering, sorting, and custom querying you can enable using these controls.

Querying Data with Declarative Syntax

The query extender control is just a container for filter expressions. Each of these filter expressions are sequentially applied to the target query, further filtering and sorting the output of queries from a LINQ or Object data source.

The following sections of the chapter provide you with a tour of the various types of expressions that can be used within a query extender to provide additional sorting and filtering capabilities.

Querying with the ControlFilterExpression

This is an expression filter that applies only when you work with a Dynamic Data website. We won’t cover a sample of this control in depth. Basically, this filter expression enables you to modify a database query using the data key of an item selected in a data-bound control. In short, this enables you to dynamically filter a query when a user selects an option from a drop-down list.

Querying with the CustomExpression

Although the QueryExtender is all about giving you the ability to do your filtering declaratively, occasionally you just need to resort to using a little bit of LINQ to get the job done. However, if you need that bit of LINQ to work in tandem with other expressions already modifying a query, you can make use of the CustomExpression class.

This works simply, you just supply a method to be invoked during the query process that enables you to inject your own modification to the query pipeline. Below is a snippet showing a custom expression and the C# method invoked by this custom expression. Although you wouldn’t normally use the custom expression to perform such trivial filtering, this at least gives you an idea of how it can be used.

image

This declaration of the query extender uses a custom expression to invoke a method called FilterWeapons during the query process. This is far better than using the traditional code-behind method because your custom query modifications are injected into the declarative query modification pipeline, enabling your code to blend seamlessly with all the other declarative sorting and filtering being done.

image

The preceding code takes the incoming query and modifies it so that whatever expressions are applied afterward will apply only to the set of weapons that meet the criteria we specified.

Querying with the DynamicFilterExpression

This is another expression that applies only when you work with an ASP.NET Dynamic Data application. This filter expression builds a database query by using the indicated DynamicFilter control, a control that is part of ASP.NET Dynamic Data framework.

For more information on filtering data using the DynamicFilterExpression in an ASP.NET Dynamic Data application, check out this MSDN link:

http://tinyurl.com/filterrows-dynamicdata

Querying with the MethodExpression

The MethodExpression class provides a means by which the developer can specify a custom LINQ query that is defined in a method. This method needs to be static and must take as its first parameter an IQueryable<T> or IEnumerable<T> object. The return value of this method can’t change the incoming parameters.

When searching for the method containing the query, the MethodExpression class first checks the class indicated by the TypeName property in the QueryExtender control. If the data source implements IDynamicDataSource, the method is searched for on the DataContext or ObjectContext object property of the data source. Finally, MethodExpression searches for the method in a template control, the base class for the page, or in a user control.

In short, there is a tremendous amount of flexibility in where you can put the custom query method, but the method itself must follow a strict format.

The following markup shows an example of specifying a MethodExpression within a QueryExtender:

image

And you might define a static method in the page (though we recommend explicitly defining the type name so you can avoid filling your code-behinds with additional logic) as follows:

image

The return value from this method is passed down the chain of filter expressions. One great advantage of putting code behind these expressions is that they can be easily reused across multiple pages. (This is another reason we recommended specifying the type name of the expression class explicitly rather than putting the expression method in the page’s code-behind.)

Sorting with the OrderByExpression

The OrderByExpression provides developers with a way of specifying a sort expression that can be applied to the query within the query extender control. The two properties of the OrderByExpression that control the sorting are the DataField and Direction properties.

The DataField property contains the name of the column on which the sorting will take place, and the Direction property indicates which direction the sorting will be done.

image

In the preceding code we sort the accounts receivable rows in descending order by the amount due. This should give us a nice list of the people who owe us money and where they live. This might not be sufficient. What if, for example, for each dollar amount, we want to sort the receivables by the age of the customer? This can enable us to see the oldest person that owes us each amount of money. We can use a ThenBy tag as a child of the OrderByExpression to accomplish this as shown below:

image

Querying with the PropertyExpression

The PropertyExpression enables the developer to use the query extender control to filter the result set based on the values of specific columns. Remember that the property expression works only with equality. For example, you cannot use a property expression to filter where the value contained in a column is less than or greater than some other value.

The following example shows how to filter a data source of ransom demands in which the ransom value is selected from a drop-down box:

image

There’s actually quite a bit of interesting functionality in the preceding code. The first thing you see is that we have a drop-down list containing a list of possible filter values for ransom demands. In this code sample, we hardcoded the values but those could easily be data bound. Next is the query extender, extending a data source called RansomDataSource. The query in that data source is filtered to contain only those rows whose RansomValue column is exactly equal to the currently selected value of the RansomValues drop-down list. This means that if the user were to select the first value in the drop-down list, the page automatically posts back, and the data source automatically filters itself based on the new ransom value.

Control Parameters enable us to continue to use declarative query extension at the same time as pulling valuable information from other controls on the page rather than potentially complicated and messy code-behind classes.

Querying with the RangeExpression

If the filter you’re looking to apply can be expressed as a range expression, this control can do the trick. A range expression is an expression in which you test whether a value is less than or greater than a target value or falls within a target range. This is a versatile expression, as shown in the following sample that filters a data source for rows in which the transaction posting date occurred within the two date periods chosen by the user with two text boxes that have jQuery-based calendar pop-ups feeding them (jQuery code is not included here because it’s beyond the scope for this chapter):

image

Querying with the SearchExpression

The search expression functionality of the query extender is one of the most powerful expressions available. It enables you to specify a field or list of fields and search those fields by doing a comparison against a search string. This search can be a “starts with”, “contains”, or “ends with” search. Gone are the days in which the developer has to hand-write these kinds of queries, which is typically an arduous, error-prone process. This expression requires you to specify the SearchType and DataFields properties, but it does the rest of the magic for you. Optionally, you can use the ComparsionType to control the case-sensitivity of the search (depending on whether the underlying data source you used supports this functionality).

As with all these expressions, you can combine them with other expressions to create rich queries without having to drop into your code-behind to do manual sorting and filtering. The following sample illustrates how to use the search expression to provide a full-featured search page (although a real-world, production search page would probably have a better UI!)

image

By now most of the markup in the preceding code sample should look familiar; however no code-behind is driving the actual querying of the database. The query extender is automatically going to modify the query (if there is anything in the search box) and filter the results every time a postback occurs. The button press causes a postback but no code in the code-behind needs to be executed because all the search logic has been rigged up declaratively in the .aspx page.

Whether having this “querying as a side-effect” is a good thing is a debate that will probably rage on for quite some time as many developers prefer to explicitly control when and how the query is performed, and obviously proponents of ASP.NET MVC Framework would have the query instigated in a controller action method rather than declaratively in the markup.

Building a Sample Page with the QueryExtender Control

Now that we’ve seen all the different options available to us when using the QueryExtender control, let’s put this all together with a real data source and some controls on the page and see how it all works as a unit.

In this sample, we point a LINQ data source (a data source for LINQ to SQL contexts) at a context that contains tables for a video game catalog database. When the data source is set up, we just need to create an ASP.NET Web Form page called GameBrowser.aspx. This page needs to have a drop-down list that enables users to filter games by Genre and a text box that enables users to search both game title and game description. Take a look at the markup for the GameBrowser.aspx page:

image

image

image

Aside from the few bits of styling information that came from choosing Autoformat on the GridView, the preceding code isn’t all that complex. The first thing we do is create a drop-down list bound to the list of genres in the video games catalog. Second, we create a text box that will eventually filter the list of games.

After the GridView, there are two LINQ data sources. The first data source points to the Genre table in the video game LINQ to SQL model. The second points to the VideoGames table; you might notice that we’re actually including a foreign key property (Genre.Name) and adding that to the anonymous type returned by the query.

Finally, we get to the query extender. The first part of the query extender is a PropertyExpression that we use to filter the GenreID property based on the currently selected value of the GenreDropDownList control. When you try this page (after creating a bogus video game catalog), you see that the form automatically reposts and requeries every time you select a new genre. Obviously you can change this behavior for a production application, but it helps drive home the point that all the QueryExtender functionality can be contained solely in the aspx markup.

The second part of the query extender is a SearchExpression. Here we’re further filtering the result set by searching the Title and Description columns of the VideoGame table for a substring indicated by the current value of the GameSearchTextBox control.

Figure 16.1 shows the output of the page after selecting a genre from the drop-down box.

Figure 16.1. Filtering using the QueryExtender.

image

Figure 16.2 shows the output of the same page after supplying some text on which to filter the games list. Note that there’s no button on this page, just hitting enter within the text box will cause a re-query after a postback.

Figure 16.2. Filtering using the QueryExtender and a SearchExpression.

image

Summary

This chapter provided you with an overview of building data-driven pages in which the filtering and sorting logic was embedded directly in the page in a declarative fashion using the QueryExtender control and its associated expressions.

By enabling you to define your queries and sort expressions declaratively in the markup, the QueryExtender also enables you to make those queries dynamic by pulling in values from other controls on the page at runtime. This makes building user-driven forms that perform searches, queries, and sorts incredibly easy.

The QueryExtender control is just one more tool for the ASP.NET developer’s arsenal for rapidly building powerful, data-driven Web Forms.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset