Friday, December 18, 2009

The On Demand Global Workforce - oDesk


Since you can't manipulate the SQL query yourself, at first, it would seem that you are 'up the creek', so to speak. However, about this time, along comes the 'DataView' class, to save the day. The solution is to assign the results returned to a DataView, and using a couple of its built in properties (Sort and RowFilter) to manipulate the data the way you want.
We'll break it up into parts here. Let's take this line:
myDataGrid.Datasource=ds.Tables("Customers").DefaultView
and change it a little.
Dim myView as DataView myView = ds.Tables("Customers").DefaultView
Here, we're creating a DataView called myView, and assigning the results of the query (ds.Tables("Categories").DefaultView) to it. Eventually, we can then assign 'myView' as the DataSource of the DataGrid, but first, we'll discuss the reasons you're reading this tutorial, the Sort and Filter properties. The Sort property is the simplest of the two, so we'll address it first. Think of the Sort property the same way you would create an 'Order By' clause in a SQL query. In an 'Order By' clause, what you're doing is ordering the ouput display by a field or fields in the database, in either Ascending or Descending order. If you add 'DESC', for descending, the default is 'ASC', so you really don't need to address this if your needs are fulfilled with the display results in ascending order.
All you really need to do to sort your dataview is to assign the field or fields you need sorted to the 'Sort' property, like this:
myView.Sort = "Region"
So, to sort by multiple fields, in a Descending order, you'd do it just like you would in an 'Order By' clause:
myView.Sort = "Region, City DESC"
Next, let's say you wanted to filter out all but those customers from a particular Region. Here, you would use the RowFilter property of the DataView. Think of the RowFilter property in the same way you would use a 'WHERE clause' in your SQL statements. You would assign data to the RowFilter proprety something like this:
myView.RowFilter = "Region = 'WA'"
This would return all Customers from the state of Washington. Naturally, you could, similarly, use any of the operators which are available in a 'Where clause', like =, >, <. <>, etc. And, naturally, you can use the Sort and RowFilter properties together in order to create a more powerful combination. Keep in mind also, that this will work just as well with a well-formed xml file as it will with database data.
In this tutorial, we've shown how to filter and sort data returned from a stored procedure or other process which has a fixed ouput, over which you have no direct control. As you can see, this adds quite a bit of power to queries and gives you more versatility in your display.

In this particular application the screen it occured on was a screen where I had applied a DataView filter to narrow the results of a DataSet.  Here is a simple app I built called "Help Desk" to show you what I am talking about.  Below the menu in the sample you'll notice I added a TextBox and a Filter button to the ToolStrip.  As you type information into the TextBox it filters the dataset by the First Name column.  Here is how that's done.
private void toolStripTextBox1_TextChanged(object sender, EventArgs e)
{
   DataView dv = adventureWorksDataSet.Contact.DefaultView;
   dv.RowFilter = "FirstName LIKE '%"+ toolStripTextBox1.Text + "%'";
   this.contactBindingSource.DataSource = dv;
}
The problem the QA team member found was not in the datalayer.  It is pretty simple to see that if you have a single quote in the toolStripTextBox1 object it is going to break the syntax of the RowFilter.  So that's the problem, now let's fix it.  I solved it quickly by doing this:

private void toolStripTextBox1_TextChanged(object sender, EventArgs e)
{
   DataView dv = adventureWorksDataSet.Contact.DefaultView;
   dv.RowFilter = "FirstName LIKE '%"+ toolStripTextBox1.Text.Replace("'", "''") + "%'";
   this.contactBindingSource.DataSource = dv;
}

This got me to thinking though, what other situations would this come up.  There may be others where you need to be careful to watch out for this but the only other similar situation was whereby you would do a select on a DataTable to return an array of rows.  For example:


AdventureWorksDataSet
.ContactRow[] rows = adventureWorksDataSet.Contact.Select("FirstName='" + toolStripTextBox1.Text.Replace("'", "''") + "'");


I then started testing all types of other characters in this situation and the single quote is the only thing I came up with that would break it.  I guess in the end we were both right.  I was right in the fact that the datalayer wouldn't be broken but the QA team memeber did in fact findbreak it with a single quote.  Note to self.  Self, if you are doing a RowFilter or DataSet Selects with a filter and are getting the input from the user, replace thesingle quotes.
I've attached the sample Help Desk solution to this post for those that want to download and play with it.  All you need is the AdventureWorks database and change the connection string to your own connection string.

I have a dataset which i fill with data from my database,
Now when i apply a rowfilter and set the datasource to my datagrid it works perfectly.

But i dont want to add it to my datagrid but to a treeview, but however i loop trough the dataset it never filters.
The idea is then when you type the first letter it get a dataset from the database containing everybody that starts with that letter then when the textbox length is larger then one apply a rowfilter


DataView dataView = dataset_filter.Tables[0].DefaultView;
    dataView.RowFilter = "artiestnaam like '" + tb_filter.Text + "%'";
    foreach (DataRowView drv in dataView)
    {
        string s = drv["artiestNaam"].ToString();
     if(tv_filter.InvokeRequired == true)
     {
      //use invoke to add to the treeview becuase of the seperate thread
      tv_filter.Invoke(new UpdateTextCallback(this.AddToTreeView), new object[]{s});
     }
     else
     {
      tv_filter.Nodes.Add(s);
     }
    }