Welcome to Catalyst Blogs Sign in | Join | Help
Dynamic Data Filtering - Table Text Search

I'm pretty happy with the number of people who have been downloading and trying out Dynamic Data Filtering.  On average there are about 20 downloads a day with around 50 page views.  There has been a lot of good feedback on both the ASP.NET forums and on the CodePlex project site 5over the last week or so.  So much actually that I am having trouble keeping up with answering the questions coming in. 

One question did catch my eye though.  It was a member of the ASP.NET forum asking about being able to search on all of the columns within a given table.  [View the Post]  Dynamic Data doesn't support this functionality out of the box, but it is flexible enough to write something yourself to do it.  The main things that makes this possible is that a single FilterTemplate can return one ore more DynamicFilterParameters which produce lambda predicates.

In this case, you can accomplish this logic of searching multiple columns in a table by saying where ProductName LIKE [Value] or ProductNumber LIKE [Value] etc...  To accomplish this in Dynamic Data Filtering you would utilize the OrExpressionParameter to create a collection of LikeExpressionParameters to do the predicate for each individual column.

I spent a little time creating a simple example which performs this logic.  I also implemented a Columns property which allows you to specify using a comma separated list the columns you want searched.  If Columns is left null or empty all columns are searched.  The aspx for the user control only contains a single asp:TextBox with the Id=TextBox1.

public partial class TableTextSearch : Catalyst.Web.DynamicData.FilterTemplateUserControlBase
{
    public string Columns { get; set; }
 
    private MetaTable Table
    {
        get
        {
            IDynamicDataSource source = this.FindDataSourceControl();
            if (source != null)
                return source.GetTable();
            return null;
        }
    }
 
    public override IEnumerable<Parameter> GetWhereParameters(System.Web.DynamicData.IDynamicDataSource dataSource)
    {
        OrExpressionParameter parameter = new OrExpressionParameter();
 
        string[] cols = null;
        if (!string.IsNullOrEmpty(Columns))
        {
            cols = Columns.Split(',');
            for (int i = 0; i < cols.Length; i++)
                colsIdea = colsIdea.Trim().ToUpper();
        }
 
        var columns = (from c in Table.Columns
                       where cols == null || cols.Length == 0 || cols.Contains(c.Name)
                       group c by c.TypeCode).ToDictionary(g => g.Key, g => g);
 
        foreach (var column in columns[TypeCode.String])
        {
            parameter.Parameters.Add(new LikeExpressionParameter()
                    {
                        Type = TypeCode.String,
                        Name = column.Name,
                        Value = TextBox1.Text,
                        Like = LikeExpressionParameter.LikeType.Contains
                    });
        }
        yield return parameter;
    }
 
    public override void LoadQueryStringParameters(System.Collections.Specialized.NameValueCollection parameters)
    {
        TextBox1.Text = parameters["TableTextSearch"];
    }
 
    public override System.Collections.Specialized.NameValueCollection SaveQueryStringParameters()
    {
        return new NameValueCollection() { { "TableTextSearch", TextBox1.Text } };
    }
 
    public override void Clear()
    {
        TextBox1.Text = string.Empty;
    }
}

To implement filters like this one you must use the DynamicFilterForm as opposed to the DynamicFilterRepeater.  The reason is that the TableTextSearch filter control is associated with any column/property in particular but the entire table instead.  It may make sense to allow the FilterAttribute to be annotated at the class level to address this.

<asp:DynamicFilterForm ID="DynamicFilterForm1" runat="server" DataSourceID="GridDataSource">
    <FilterTemplate>
        <div>
            Search
        </div>
        <div>
            Keyword: 
            <dd:TableTextSearch runat="server" ID="TableTextSearch" />
            <asp:LinkButton ID="LinkButton4" runat="server" CommandName="Search">Search</asp:LinkButton>&nbsp;&nbsp;
            <asp:LinkButton ID="LinkButton5" runat="server" CommandName="Clear">Clear</asp:LinkButton>
        </div>
    </FilterTemplate>
</asp:DynamicFilterForm>

To build upon this example it would be nice to be able to search the DisplayText of foreign columns and potentially non text values.  For example if the user entered a string which can be converted to a date, search all DateTime columns.

Posted: Friday, October 17, 2008 7:11 PM by jheyse
Filed under: , ,

Comments

Justin said:

Josh your filters are great and I'd love to use them, but my application currently uses Dynamic Data Futures filters, which (for starters) inherit from FilterUserControlBase, not your Catalyst classes. Have you tried to integrate the two projects at all? I'd love to know if it's possible at all to use both types of filters behind a DelegatingFilter class.

# October 22, 2008 10:38 PM

jheyse said:

Justin,

I had started developing Dynamic Data Filtering back in February well before the futures project had been released so I couldn't take it into my design.  I haven't had the opportunity to look into integrating the futures project and Dynamic Data Filtering.  I do know that the ASP.NET team is looking into using a design similar to Dynamic Data Filtering for the next release.  What are you using the futures for?  sjnaughton has a pretty good series on the futures project and is now going to be looking into Dynamic Data Filtering.  He would probably be the best resource for this.

# October 23, 2008 9:27 AM

bmbutters said:

Hi Josh, I stumbled upon your samples purely by accident and they're greaaattt. I was wondering however, if it was possible to implement a solution that uses Linq to Entity as opposed to Link to SQL as this is being depracted?

# December 2, 2008 2:59 AM

jheyse said:

bmbutters,

I've spent a little time looking into Linq-to-Entities and the issue is that the EntityDataSource does not allow the same capabilities as the LinqDataSource.  It would be possible to make this work, but it would require a great deal of hacking with the use of reflection to access private members.

Josh

# December 2, 2008 3:51 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS