尽管检查了null参数,Linq-to-SQL抛出NullReferenceException

时间:2009-12-20 02:39:25

标签: c# sql linq linq-to-sql c#-3.0

我正在尝试在LinqPad中编写Linq-To-SQL查询,以帮助用户从旧表迁移到新表。此迁移的一部分是将所有地址存储在单独的表中。我正在使用以下查询来确定新表中是否存在用户的地址(因此我没有重复的条目):

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;

此处,'u'代表旧用户。旧表中的某些地址包含Street_address,City,State和/或Zipcode的空条目。此外,一些地址是重复的,除了套管(因此ToLower())。

尽管在查询中检查了null参数,但如果任何用户的地址参数为null,我仍然会得到NullReferenceException。

我做错了吗?或者有更好的方法来实现我的需求吗?

1 个答案:

答案 0 :(得分:2)

<强>更新

嗯,看起来这比我原先想象的要复杂得多。使用StringComparison重载的{。{3}}变为String.Equals。但是,您收到错误的事实意味着Linq-to-SQL正在尝试获取整个表达式并将其转换为SQL。这反过来意味着所有比较都将根据数据库的本机排序规则进行 - 默认情况下不区分大小写。因此,尽管Linq-to-SQL不支持不区分大小写的比较,但您可能不需要进行不区分大小写的比较,因为默认情况下您可以依赖SQL Server来执行这些比较。

因此,如果您没有将表中字符串列的排序规则从不区分大小写(默认值)更改为区分大小写,则以下代码应该有效:

var addresses = from a in Addresses 
                where String.Equals (u.Street_address, a.Street1)
                      && String.Equals (u.City, a.City)
                      && String.Equals (u.State, a.State)
                      && String.Equals (u.ZipCode, a.Zip)
                select a;

这可能也有效:

var addresses = from a in Addresses 
                where u.Street_address == a.Street1
                      && u.City == a.City
                      && u.State == a.State
                      && u.ZipCode == a.Zip
                select a;

但是,基于我对not supported by Linq-to-SQL的阅读(摘录如下),我怀疑只使用==(而不是String.Equals()可能不起作用):

  

空语义

     

LINQ to SQL没有   强制使用null比较语义   SQL。比较运算符是   语法翻译成他们的SQL   等价物。出于这个原因,   语义反映了SQL语义   由服务器或连接定义   设置。例如,两个空值   在违约情况下被视为不平等   SQL Server设置,但你可以   更改设置以更改   语义。 LINQ to SQL没有   考虑服务器设置   翻译查询。

     

与文字null的比较是   翻译成适当的SQL   version(为null或不为null)。

换句话说,如果我正确地阅读此MSDN文本,听起来Linq-to-SQL会将==转换为T-SQL中的=,而(如您的实验所示)字符串.Equals被正确翻译为IS NULL的支票,然后使用=进行检查。如果您有机会仅测试==,我有兴趣了解Linq-to-SQL是否会发出IS NULL检查。

鉴于此处的复杂性(Linq-to-SQL将C#转换为SQL,结果转换回C#),在这种情况下,最好的选择是尝试多种变体(例如== vs. Equals())并选择一种这是有效的,因为有足够的移动部件,很难提前预测哪种变化最好。

OLD ANSWER(忽略此项):

考虑使用静态this MSDN article方法而不是==ToLower()。您将避免空引用问题(并简化您的代码),因为空值可以传递到该方法,并且它支持不区分大小写的检查。

var addresses = from a in Addresses 
                where String.Equals (u.Street_address, a.Street1, StringComparison.OrdinalIgnoreCase)
                      && String.Equals (u.City, a.City, StringComparison.OrdinalIgnoreCase)
                      && String.Equals (u.State, a.State, StringComparison.OrdinalIgnoreCase)
                      && String.Equals (u.ZipCode, a.Zip, StringComparison.OrdinalIgnoreCase)
                select a;

虽然你的数据库已经不区分大小写了,但是根据Linq-to-SQL如何分割SQL和C#代码之间的工作,你可能根本不需要不敏感性检查 - 尽管如果它是我,我会相当安全,并确保你总是执行案件检查。