2015-02-23 55 views
3

我有这个疑问:SQL Server在查询时是否自动修剪nvarchar字段?

select '[' + p.Firstname + ']' from Person p 
where p.Firstname = 'Johanne' 

在该表中,我有多个personne谁拥有这个名字,和一些对价值尾随空间(价值的不良插入,它会被纠正)。

那么为什么这个查询给我带来这样的结果(我插在括号中以可视化的空间):

[Johanne] 
[Johanne ] 
[Johanne ] 
[Johanne] 

这是一个配置的事情吗?真正的查询来自实体框架6,但这个例子也是如此。我怎样才能防止它?

谢谢!

编辑:我可以使它工作使用EF6和System.Data.Entity.SqlServer.SqlFunctions.DataLength方法是这样的:

ctx.Person.FirstOrDefault(p => p.FirstName == "Johanne" && SqlFunctions.DataLength(p.FirstName) == "Johanne".Length); 
+0

我注意到,如果我在where子句中的值是“Johanne”(最后有一个空格),我仍然会得到相同的结果。 – Shimrod 2015-02-23 20:19:50

+0

正确,但在默认情况下,在Sql Server中,如果你有一个前导空间,那么它将不会匹配ie。 '约翰'不会在你的where子句中返回任何结果。 – Igor 2015-02-23 20:23:02

+1

如果您在此处使用'N'字符串,它会起作用吗? 'p.Firstname = N'Johanne''? 'N'告诉它使用Unicode,它将匹配列的类型。 – 2015-02-23 20:24:15

回答

3

的SQL Server遵循ANSI/ISO SQL-92规范(第8.2节,一般规则#3)如何将字符串与空格进行比较。 ANSI标准要求在比较中使用填充字符串,以便在比较它们之前匹配它们的长度。填充直接影响WHERE和HAVING子句谓词的语义以及其他Transact-SQL字符串比较。例如,对于大多数比较操作,Transact-SQL认为字符串'abc'和'abc'是等价的。

此规则的唯一例外是LIKE谓词。当LIKE谓词表达式的右侧具有带尾随空格的值时,在比较发生之前,SQL Server不会将这两个值填充到相同的长度。由于定义LIKE谓词的目的是为了方便模式搜索而不是简单的字符串相等性测试,所以这并不违反前面提到的ANSI SQL-92规范的一部分。

参见:http://support2.microsoft.com/kb/316626/en-us

+0

另请参阅:http://richarddingwall.name/2007/12/28/t-sql-equality-operator-ignores-trailing-spaces/ – 2015-02-23 20:31:13

+0

感谢您的解释安东尼!任何想法如何使用EF6克服这个问题?我的意思是,如果我搜索价值'约翰'(与空间),我不想看到没有空格的值。 – Shimrod 2015-02-23 20:47:31

+0

根据我所阅读的内容,您应该可以像使用(一路阅读)一样使用,但根据文章,您应该非常了解性能问题。我还读到EF“包含”在这种情况下会产生一些后果,并且沿着类似的方式运行。请参阅EF中的“实施”,地址为http://stackoverflow.com/a/11371822/1662973 – 2015-02-24 19:20:53

2

我不知道在EF但在TSQL我用数据长度

DataLength

数据长度将返回包括尾随空白长度
莱恩将返回长度不包括尾随空格

and DataLength(p.Firstname) = Len('Johanne') 
+0

是的,我确实在TSQL中尝试了'DataLength'(成功)。然而,当我在EF6中使用'string.Length'时,它只转换为'LEN',我不知道如何让EF6使用'DataLength' – Shimrod 2015-02-23 23:03:38

+0

其中'['+ p.Firstname +']'=' [Johanne]' – Paparazzi 2015-02-24 00:49:06

2

您找到d在Sql中创建一个新视图并将该视图映射回EF对象。该视图可以包含字段的长度,在使用DataLength的选择中,你知道你想匹配,然后你可以在你使用EF时在where子句中对它进行过滤。 或者,您可以创建一个Sql Stored Proc,它使用LIKE进行比较,而不使用通配符(产生期望的结果),并将其映射回您的代码并在EF中的Where语句中调用它。


使用视图

Create View MyCustomView 
AS 
SELECT [column1,column2,etc], DATALENGTH(FirstName) AS FirstNameLength 
FROM Person 
GO 

然后你的EF是:

Persons.Where(p => p.FirstNameLength == "Johanne".Length && p.FirstName == "Johanne"); 

要使用存储过程

CREATE PROCEDURE [dbo].[GetPersons] 
firstName int = null 
AS 
BEGIN 
SET NOCOUNT ON; 
select [your fields here] 
from persons 
where FirstName like @firstName 
END 

在C#确保您的映射是正确的,然后

this.Database.SqlQuery<Person>("GetPersons","Johanne"); 

EF6还支持在执行之前直接编辑在的DbContext的SQL。你可以开发一些自定义代码来替代=,就像在特定情况下一样,但在你做之前可能更容易尝试上面的第一个。

+0

我发现使用'SqlFunctions'类更简单的方法,请参阅我的编辑。但是非常感谢您的解决方案,它们是很好的替代品! – Shimrod 2015-02-24 14:04:53