views:

126

answers:

1

Over and over, I find myself developing WinForm business application screens that have a bunch of text boxes for search criteria, then a search button. These are mapped into an expression using Linq, then passed onto my Linq2Sql layer.

I'd like to create an easy way to "bind" these textboxes to the underlying query using different options like "contains", "startswith", "exactmatch", etc...

What I'm imagining is something like this (note SearchBinderT is imaginary):

SearchBinder<Customer> searchBinder = new SearchBinder<Customer>();
searchBinder.Bind(txtFirstName, a=>a.FirstName, SearchBinderOptions.StarsWith);
searchBinder.Bind(txtLastName, a=>a.LastName, SearchBinderOptions.StarsWith);
searchBinder.Bind(txtTelephone, a=>a.Phone, SearchBinderOptions.Equals);
searchBinder.SetAction(btnSearch, MyMethodThatHandlesTheExpressionTreeAndFillsTheResults);

Then clicking search would automatically generate the expression tree where the textboxes weren't empty and execute the search. But thats only one pattern in my head - there are many more. I'm mainly focused on rapid application development.

  • What design pattern(s) would you use for this (or is what I'm thinking good)?
  • How would you handle other datatypes (dates/numbers with less than/greater than)
A: 

Wouldn't the delayed execution and captured state of lambdas solve this?

Predicate<Customer> searchQuery = c => {
   c.FirstName.StartsWith(txtFirstName.Text)
   && c.LastName.StartsWith(txtLastName.Text)
   && c.Phone == txtTelephone.Text;
}

void btnSearch_Click(object sender, EventArgs e) {
    return IEnumerable<Customer>.Where(searchQuery);
}

Since searchQuery isn't executed until the button clicks, there's no need to abstract out the comparisons to "builder" components. There's the whole multithreaded issue with accessing the textboxes, but you could use an Expression<T> instead and decompose and rebuild with Control.Invoke. Or, just write it with Invoke to begin with. Or, send it back to the UI thread to run.

But, if you really wanted to go with your design - I'd suggest using Expression<T> instead of the comparison operators you have. It's more flexible, and will save you a good bit of work.

As for design pattern, the closest I know of would be a Query Object - which [N]Hibernate has in the form of Criteria. It deals more with building dynamic queries though, not binding to the UI elements (which, again, I'm not seeing the point of). In your example, your query is hardcoded - so I'm not sure what the benefit would be.

Mark Brackett
The builder component would have the logic to build the predicate based on whether the text boxes were filled out or not. an empty text box should be left out of the query. You predicate doesn't take that into account.
TheSoftwareJedi
Okay - then it sounds like you want a Query Object that's databound to the controls. If the values are empty, you'll leave them out of the query (which is the normal Query Object pattern).
Mark Brackett