我正在尝试在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。
我做错了吗?或者有更好的方法来实现我的需求吗?
答案 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#代码之间的工作,你可能根本不需要不敏感性检查 - 尽管如果它是我,我会相当安全,并确保你总是执行案件检查。