(Print this page)

Use dynamic Linq queries to build a search feature
Published date: Tuesday, November 25, 2014
On: Moer and Éric Moreau's web site

All applications presenting data need to provide a kind of search feature integrated in it. If you are lucky enough, the data grid component you are using directly exposes this feature. But maybe your component is not offering this feature or you are not using a control other than a datagrid or you want to offer something different to your user.

With the help of an old (2007) blog post from the VB team, this article shows you a different yet generic way of searching a Linq data source and considering that almost anything and everything can be exposed as is today, it shouldn’t be too difficult. The blog post was providing a Windows Forms control that we will reuse here. If you are using another presentation model than a Windows Forms, there is still a whole lot of code reusable in that original blog post.

Demo code

The solution is composed of 3 parts (or projects).

The first project named DynamicCondition is a VB only class-library took from the refered blog post that I have just slightly modified to fix some behaviors that I found irritating. I didn’t want to convert it all to C# as it could be reuse (reference) as is from a C# project without any problems as shown here.

The 2 other projects (DynamicLinqCS and DynamicLinqVB) are the Windows Forms clients UI showing the grid along with the generic search component.

The solution was created with Visual Studio 2013 targeting the .Net Framework 4.5 but can surely be reused in any version of the .Net Framework supporting Linq.

Figure 1: The demo application in action

The famous blog post

This famous blog post I am referring since the beginning from which it all started is titled Implementing Dynamic Searching Using LINQ. It is worth having a quick look by the way.

What is it all about?

The thing that is so great about the code and the control provided in this blog post is that it is generic. The control does not have knowledge about the data structure it will be used with while still showing the field names and being able to handle properly their datatype (booleans are shown using a CheckBox, dates are shown using a DateTimePicker, and everything else showing a plain-old TextBox).

In my form’s Load event, I have this line:

ConditionBuilder1.SetDataSource(_list)

In this example, _list is a List of Customer (which in turn is a class of this project exposing some properties to test the dynamic component).

When you pass a collection of objects to the SetDataSource method, by using reflection the list of properties of that object will become the list of fields available in a combo box of the search component.

The control automatically recognize some data types and will accordingly show a CheckBox, or a DateTimePicker, or a TextBox to best fit the datatype of the selected property.

The control also let you pick one of the operator (Equals, >, <, Like, …).

So it let you select the field, the operator, and enter a value. The basic information needed for a dynamic search.

Generating the condition

Now that the search control has been filled with the values we want to search for, we need to pump back those in order to filter our datasource. While executing the application, after having filled the control with at least one value, click the “Refresh Grid” button.

This is the code found in this event handler:

'Get the Condition out of the control
Dim c = ConditionBuilder1.GetCondition(Of Customer)()
If (c Is Nothing) Then
    MessageBox.Show("No condition built. Review your criteria!")
Else
    'Filter out all objects that don't match the Condition
    'Note that the query does not actually get executed yet to due to deferred execution
    Dim filteredQuery = _list.Where(c)

    'We can now perform any other operations (such as Order By or Select) on filteredQuery
    Dim query = From row In filteredQuery
                Order By row.Id
                Select row

    'Executes the query and displays the results in DataGridView1
    DataGridView1.DataSource = query.ToList()
End If

The GetCondition method of the control, will use the field names, the datatype of the fields, the operator you have selected and the value entered to build a lambda expression matching your data source. I store this condition into the c variable.

If a lambda expression is returned, it is passed to the Where extension method of your collection to filter the list into the new filteredQuery variable.

This new object is then sorted by Id into another new variable called query. You can do just about anything you want here. Your data is already being filtered.

Finally, the source of the grid is set to the query variable to display the filtered output.

Remember that LINQ defers execution of the query until it is really needed. So here the filteredQuery variable does not store the filtered data. It is really a query that has not been executed yet that knows which data source to use and what filter to apply. Later, when the query variable gets declared and initialized, it does not contain data, it just contains a query. In this case here, the query really gets executed when the ToList method is called.

Setting a reference

If you want to reuse this component in your own project, the first thing you will need to do is to add a reference to the DynamicLinq project. I strongly encourage you to add the project to your solution to ease the debugging (and don’t forget to rebuild your solution to see the component in your toolbox). After this step has successfully been done, you should see the ConditionBuilder appears in your toolbox and you will be able to drag one to your Windows forms application.

Number of lines

My demo application is showing 2 lines of criteria. This can be set to whatever the value you want or need.

When you place an instance of the ConditionBuilder control on the form, you have access to its Lines property. This let you set the number of condition that can be set.

If you don’t give enough space to the control, a scroll bar will automatically b shown.

And/Or

When you have multiple criteria, you don’t always want them to be added (AND operator). By clicking the blue AND to the left of the second row, it will toggle between the AND and the OR operators.

LIKE operator

If you are using the Like operator, you can use the * wildcard character.

Further enhancements

I have already included some improvements to the control. The first improvement is that now Like operator is not case sensitive (but the other operators are). The empty values are now properly ignored.

But other improvements would be great. For example, a variable number of lines would be great. User could add or delete conditions. Also, the And/Or operators are not prioritize.

Conclusion

This control is surely not perfect but it is a step in the right direction if you want to build that kind of feature in your application.

Also, by looking at the code of the control, you can learn a lot on how to build dynamic condition.


(Print this page)