Saturday, February 7, 2009

Easing Constraints Without Duplicating Queries

I had a rather common problem at work that I created a rather elegent solution for.  Lets say for instance you had a database table that contained a list of businesses, the city they operated in, the state they operated in, and their FEIN.  You were given a list of business names, and asked to find the correct FEIN for each business. You need to search for the business by name, city, and state first. If you don't find it, then search for the business by name and city. If you still don't find it, you finally just need to search by the name, returning the first record each time if there are duplicates. You've used LINQ to SQL to get a collection of the data, and now you need to return the best match.  At first you may do what I did at first, something like this:

var feins1 = from business in Database
where business.Name == name
&& (business.City == city)
&& (
business.State == state)
select business.FEIN;

if (feins1.Count() > 0) {
return feins1.First();
}

var feins2 = from business in Database
where business.Name == name
&& (business.City == city)
select business.FEIN;

if (feins2.Count() > 0) {
return feins2.First();
}

var feins3 = from business in Database
where business.Name == name
select business.FEIN;

if (feins3.Count() > 0) {
return feins3.First();
}


You reach for the ctrl-c and ctrl-v on your keyboard, and suddenly feel really dirty. What if another criteria needs to be added? You'll have to add another criteria to each where statement, as well as adding an entirely new query. I spent a few minutes thinking about it, and came up with this solution:

    for (int i = 0; i < 3; i++) {
fein = GetBestFEIN("Good Times Inc", "Indianapolis", "IN", i > 1, i > 0);

if (fein != string.Empty) {
break;
}
}
return fein;
}

private string GetBestFEIN(string name, string city, string state, bool skipCity, bool skipState) {

var Database = from i in new string[] { "0", "1", "2", "3" }
select new { Name = i, FEIN = i, City = i, State = i };

var feins = from business in Database
where business.Name == name
&& (
skipCity || business.City == city)
&& (
skipState || business.State == state)
select business.FEIN;

if (feins.Count() == 0) {
return string.Empty;
}
else {
return feins.First();
}
}





Now if another criteria is added, you just need to increase the for each loop by one, and add another parameter. I made my change, and went home feeling a lot cleaner.

No comments: