【问题标题】:How to tell Linq to Entities to use 'Like' for string equality?如何告诉 Linq to Entities 使用 'Like' 进行字符串相等?
【发布时间】:2016-09-02 21:15:19
【问题描述】:

问题

当我用 Linq 写实体时

context.MyTable.Where(t => t.Name == "Test");

它转换为以下sql:

select * from MyTable where Name = 'Test'

我想在 Linq 中为实体编写一个表达式,将转换为:

select * from MyTable where Name like 'Test'

有什么方法可以实现吗?

注意-我也尝试了EqualsCompareTo == 0,但无济于事。

背景故事

我想使用Like而不是=的原因是因为如果你使用=,字符串末尾的空格会被忽略,但如果你使用Like,它就可以工作(看到这个问题:Why the SQL Server ignore the empty space at the end automatically?,还有这个:Linq to Entity comparing strings ignores white spaces)。

编辑:为什么它不是 How to do SQL Like % in Linq? 的重复项

该问题要求类似 %,可以使用 Contains/StartsWith/EndsWith 完成,但这不是同一个问题,我想要完全平等,所以这些对我没有帮助。 这个问题的答案看起来很有希望,使用SqlMethods.Like,所以我尝试了

context.MyTable.Where(t => SqlMethods.Like(t.Name, "Test")

但我收到以下错误:

{"LINQ to Entities 无法识别方法 'Boolean Like(System.String, System.String)' 方法,并且该方法无法转换为存储表达式。"}

【问题讨论】:

  • @Reinard + @L.B,不,它不是重复的。我想做没有 % 的 Like,Contains 在这里不起作用。
  • 我建议您在查询中使用context.MyTable.Where(t => t.Name.TrimEnd() == "Test"),看看是否能达到您想要的结果。
  • @AnthonyPegram 这无济于事。我想要相反的行为,当我不想匹配时,我会得到匹配。
  • 那我一定是完全误解了 MSDN 关于 LIKE 的文档。 “如果查询中的比较是返回所有带有字符串 LIKE 'abc'(没有空格的 abc)的行,则返回所有以 abc 开头并且有零个或多个尾随空格的行。” msdn.microsoft.com/en-us/library/ms179859.aspx
  • IMO OP 应该准确说明应该和不应该匹配的字符串,包括两边尾随空格的所有示例(数据库有“test”、“test”、“test”,你什么时候想要“测试”、“测试”和“测试”来匹配这 3 个?) OP 对 LIKE 如何工作的概念很可能是不正确的,所以如果人们回答他的问题,他将不会得到他想要的结果。他说 LIKE 不会忽略空格,但它确实会,但仅在某些情况下。 LIKE 比较 anthony 和 itsme 发现的“完全相等”。编辑:评论系统会删除除 1 个尾随空格之外的所有内容..

标签: c# sql-server entity-framework linq-to-entities


【解决方案1】:

我是official:

SQL Server 遵循关于如何比较字符串和空格的 ANSI/ISO SQL-92 规范(第 8.2 节,通用规则 #3)。

如果你不想要,那就太麻烦了。

一个不忽略空格的 SQL 函数是 DATALENGTH。幸运的是,我们可以在 EF 查询中使用该函数,因为它是SqlFunctions 中的函数之一。所以你可以添加一个额外的检查 DATALENGTH 是否等于搜索字符串的长度:

var searchText = "Test";
var result = context.MyTable
                    .Where(t => t.Name == searchText
                             && SqlFunctions.DataLength(t.Name)
                                  == SqlFunctions.DataLength(searchText))

比较t.NamesearchTextDataLength 是必要的,因为DataLength 返回的是字节数,而不是字符数(Ivan,感谢您的评论)。

【讨论】:

  • 嗨 Gert,像往常一样有趣的解决方案,但 DataLength 返回字节数,所以我想你也需要将它应用于参数,例如SqlFunctions.DataLength(t.Name) == SqlFunctions.DataLength(searchText)
  • @IvanStoev 是的,我昨晚很晚才这样做。睡觉时带着小声抱怨比特和字节、变音符号/unicode 的长度等。这让我怀疑 DATALENGTH 无论如何返回什么。今天很忙,然后我看到了你的建议。很高兴被采纳!
【解决方案2】:

有趣的是,我写了原始问题的答案,并且同意这个边缘案例不是那个的重复。

根据您的查询结果大小,您能否在客户端运行第二遍:

var result = iQueryableSource
    .Where(i => i.Field.Contains("Fred"))
    .AsEnumerable()
    .Where(i => i.Field == "Fred");

我同意,如果您的数据集很大,这可能是个问题。

另一种完全在服务器端的方法是结合 StartsWith 和 EndsWith:

var result = iQueryableSource
        .Where(i => i.Field.StartsWith("Fred"))
        .Where(i => i.Field.EndsWith("Fred");

【讨论】:

  • 也许是第一种方法,尽管我希望完全是服务器端的东西。第二种方法是一个错误:如果我以你的为例,它将与“FredFred”匹配。
  • 对不起,我无法访问 sql server 来测试这个。在第二种方法中添加长度检查怎么样?
  • 嗯,是的,这基本上是 Gert 提出的解决方案(然后我不需要开始和结束)。
猜你喜欢
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多