views:

39

answers:

1

This function is used to return a contact list for a users search input. The number of search terms is always at least one, but could be many.

public IList<Contact> GetContacts(string[] searchTerms)
{
    using (dbDataContext db = new dbDataContext())
    {
        var contacts = from _contacts in db.Contacts
                       orderby _contacts.LastName ascending, _contacts.FirstName ascending
                       select _contacts;

        foreach (string term in searchTerms)
        {
            contacts = (IOrderedQueryable<Contact>)contacts.Where(x => SqlMethods.Like(x.FirstName, "%" + term + "%")
                                                                    || SqlMethods.Like(x.MiddleName, "%" + term + "%")
                                                                    || SqlMethods.Like(x.LastName, "%" + term + "%")
                                                                    || SqlMethods.Like(x.PreferredName, "%" + term + "%"));
        }

        return contacts.ToList<Contact>();
    }
}

The problem is in the loop. Only the last search term is ever used, even though the generated sql looks correct (as in the correct amount of clauses are generated for the number of terms).

Example - if I pass two terms ('andr','sm'), the sql generated shows two blocks of clauses as expeted, but only uses 'sm' as the param in both blocks.

What am I doing wrong? Should I even be using SqlMethods?

+5  A: 

Maybe the problem is with capturing the loop variable term. Try this:

foreach (string term in searchTerms) 
{
    string t = term;  
    contacts = ... // use t instead of term
}
Henrik
You my friend are a genius. Works!!!
IckleMonkey
Do you know why this would happen?
IckleMonkey
because you are closing over a loop variable, so when you come to run the query term is always the last value in the passed in array. see this question: http://stackoverflow.com/questions/227820/why-is-it-bad-to-use-a-iteration-variable-in-a-lambda-expression
Matt Ellen
Is this behaviour unique to linq 2 sql? Because of the delayed nature?
IckleMonkey
no it's not about linq. It's about closures.
Stephane