I’m trying to write Linq-To-SQL queries in LinqPad to help migrate users from old tables to new tables. Part of this migration is storing all addresses in a separate table. I’m using the following query to determine if a user’s address exists in the new table (so I don’t have duplicate entries):
var addresses = from a in Addresses where ((u.Street_address == null && a.Street1 == null) || (u.Street_address != null && a.Street1 != null && a.Street1.ToLower() == u.Street_address.ToLower()))
&& ((a.City == null && u.City == null) || (a.City != null && u.City != null && a.City.ToLower() == u.City.ToLower()))
&& ((a.State == null && u.State == null) || (a.State != null && u.State != null && a.State.ToLower() == u.State.ToLower()))
&& ((a.Zip == null && u.Zipcode == null) || (a.Zip != null && u.Zipcode != null && a.Zip.ToLower() == u.Zipcode.ToLower()))
select a;
Here, ‘u’ represents an old user. Some addresses in the old table contain null entries for the Street_address, City, State, and/or Zipcode. Also, some addresses are duplicates, except for casing (hence the ToLower()).
Despite checking for null parameters in the query, I still get a NullReferenceException if any of the user’s address parameters are null.
Am I doing something wrong? Or is there a better way to accomplish what I need?
UPDATE:
Hmmm, looks like this is more complex than I originally thought. Turns out String.Equals with a StringComparison overload is not supported by Linq-to-SQL. But, the fact that you get the error means that Linq-to-SQL is trying to take the entire expression and turn it into SQL. Which in turn means that all comparisons will happen according to the native collation of the database– which by default is case-insensitive. So even though Linq-to-SQL won’t support case-insensitive comparisons, you probably don’t need case-insensitive comparisons since you can rely on SQL Server doing them by default.
So, provided you haven’t changed the collation of your string columns in your table from case-insensitive (the default) to case-sensitive, the following code should work:
It’s possible this may work too:
But, based on my reading of this MSDN article (excerpted below), I suspect that only using
==(instead of String.Equals() may not work) :In other words, if I’m reading this MSDN text correctly, it sounds like Linq-to-SQL translates
==into=in T-SQL, while (as your experiment showed) String.Equals is translated correctly as a check forIS NULLfollowed by a check using=. If you have a chance to test just==, I’d be interested to see whether Linq-to-SQL emits theIS NULLchecks or not.Given the complexity here (Linq-to-SQL translating C# into SQL, and results back to C#) your best bet in cases like this is to try multiple variations (e.g. == vs. Equals()) and pick the one that works, since there are enough moving parts that it’s hard to anticipate ahead of time which variation will work best.
OLD ANSWER (ignore this):
Consider using the static
String.Equalsmethod instead of==andToLower(). You’ll avoid the null-reference problems (and simplify your code) because nulls are OK to pass into that method and it supports a case-insensitive check.Although if your database is already case-insensitive, depending on how Linq-to-SQL splits the work between SQL and C# code, you may not need the insensitivity check at all– although if it were me, I’d rather be safe and enure you always enforce the case check.