views:

67

answers:

4

I have a page where you can search for people. They can either get a list of all people, or filter it by certain criteria such as first or last name.

So far, I have been trying trying to use the technique detailed in this question.

So my code looks like

string firstname=...
string lastname=...

var people=from p in People.All()
           where (firstname==null || firstname.ToLower()==p.FirstName.ToLower()) &&
                 (lastname==null || lastname.ToLower()==p.LastName.ToLower())
           select p;

I get a null reference error when building the query however when both firstname and lastname is null. Removing the where clause gets rid of the error.

Why would this not work? Does C# try to evaluate the second part of each part of the where clause? It shouldn't because of the short-circuited OR right?

A: 

Make sure it's not null before calling the ToLower:

(firstname==null || (firstname!= null && firstname.ToLower()==p.FirstName.ToLower()))
samiz
A: 

It doesn't work when both are null because the first part of the statement will evaluate to true, disallowing short-circuiting of the evaluation. Why not use equivalency rules to flip the statement?

(firstName != null && firstName.ToLower() == p.firstName.ToLower()) 

EDIT: I wrote the following up and ran it successfully in LINQPad 4, with no issues. I'm assuming that the call to People.All() simply returns an IQueryable<People> with the full set of records? Maybe post your exception text here so we can see if there's something you've inadvertently missed?

void Main()
{
    string a = null;
    string b = null;
    var peeps = new List<Person> { 
        new Person { 
            FirstName = "John",
            LastName = "Connor"
        },
        new Person { 
            FirstName = "Sarah",
            LastName = "Connor",
        },
        new Person { 
            FirstName = "Cletus",
            LastName = "Handy"
        }
    };

    var somePeeps = from p in peeps
        where (a == null || a.ToLower() == p.FirstName.ToLower()) 
            && (b == null || b.ToLower() == p.LastName.ToLower())
        select p;

    somePeeps.Dump();

}

public class Person
{
    public string FirstName { get; set;}
    public string LastName { get; set;}
}
Josh E
if the first part is true, then it shouldn't evaluate the second part due to short-circuited OR though.
Earlz
+1  A: 

you don't need to call ToLower() use string.compare instead with ignoreCase

string.Compare(firstName, p.FirstName, true) 
foila
+1  A: 

Use string.Equals:

from p in People.All()
where (firstname == null || string.Equals (firstname, p.FirstName, StringComparison.InvariantCultureIgnoreCase)) &&
      (lastname == null || string.Equals (lastname, p.LastName, StringComparison.InvariantCultureIgnoreCase))
select p

Not only does this avoid the null problem, but it forces you to specify a string comparison type (a good thing). In other words, you specify whether to use rules specific to the local or invariant culture when performing the case-insensitive comparison.

Joe Albahari
are you one of the Albahari brothers of LINQPad fame? Just curious...
Josh E