【问题标题】:Weird behavior in Entity Framework Linq in string EndsWith method字符串 EndsWith 方法中实体框架 Linq 中的奇怪行为
【发布时间】:2015-03-12 11:45:49
【问题描述】:

背景

我有一个只包含一列的表:名称。 里面只有四行,比如说

| Name      |
| test1.com |
| test2.com |
| test3.com |
| test4.com |

问题

如果我查询

var email = "a@test2.com";
Table.Where(x => email.EndsWith(x.Name));

我会得到一个空列表。但是如果我先查询所有行并像这样计算内存中的位置

var email = "a@test2.com";
Table.ToList().Where(x => email.EndsWith(x.Name));

我会得到一个列表,其中只包含正确的 test2.com。

第一个查询生成的 SQL 是

SELECT "Extent1"."Name" AS "Name"
FROM "USER"."Table" "Extent1"
WHERE (( NVL(INSTR(REVERSE(:p__linq__0), REVERSE("Extent1"."Name")), 0) ) = 1)

我尝试将 :p__linq__0 替换为 'a@test2.com' 并在 SQLDeveloper 中运行查询,结果是正确的。

更多信息

如果我将 EndsWith() 更改为 Contains(),问题就会消失。这是为 Contains() 生成的 SQL

SELECT "Extent1"."Name" AS "Name"
FROM "USER"."Table" "Extent1"
WHERE (( NVL(INSTR(:p__linq__0, "Extent1"."Name"), 0) ) > 0)

您知道 EndsWith 或 REVERSE 方法有什么问题吗?

环境

  • EF5.0
  • .NET4.5
  • Oracle11g
  • ODP.NET11.2 第 3 版

【问题讨论】:

  • 这是一个很好的例子,说明了为什么在直接将 IQueryables 与 SQL 一起使用时我们应该始终检查 SQL EntityFramework Generates。我无法解释为什么它会生成它所生成的 SQL……但是检查我生成的几乎每个 IQueryable 已成为一种常见的做法。

标签: c# linq entity-framework oracle11g odp.net


【解决方案1】:

这条线与我有关,是使用 EF 的人的常见缺陷:

Table.ToList().Where(x => email.EndsWith(x.Name));

Table.ToList() 部分是最糟糕的部分,因为这实际上会将整个表 实体化到内存中,然后在 C# 中执行 EndsWith。 这一行:

Table.Where(x => email.EndsWith(x.Name));

我会在一般原则上提醒这种方法,因为当表格增长到合理的大小时它会非常缓慢。您可以在查询到达数据库之前完成繁重的工作,方法是在构建查询时从电子邮件中拆分域:

var email = "a@test2.com";

/* You should null check this of course and not just assume a match was found */
var domain = Regex.Match(email , "@(.*)").Groups[1].Value; 

/* Note: ToList() materialisation happens at the end */
var result = Table.Where(x => x.Name == domain).ToList();  

此外,如果您需要匹配存储电子邮件的列的域名,那么我的首选方法是拆分电子邮件并将域名存储在您索引并仅匹配的单独列中,这将扩展并且更容易管理。请记住,现在数据很便宜……尤其是与不可索引的表扫描相比。

还要记住(对于这两种情况)您的数据库设置为 CI(不区分大小写)

【讨论】:

  • 那么,EF 不支持 EndsWith 吗?我看不到任何文件描述了这一点。有链接吗?
  • 不,答案就是我上面所说的......你不需要它。只需在 c# 中提取域名并将其传递给查询。确保您重新阅读我的答案,因为我认为您不太了解 c# 和 sql 之间的界限。当您在 EF 表实体上调用 ToList() 时,您正在物化(拉入内存)整个表,这对于性能来说是可怕的并且不会扩展。这能把事情弄清楚吗?还有什么令人困惑的地方吗?
  • 我知道 ToList() 将所有行拉入内存。我只是好奇为什么 EndsWith 不起作用。生成的 SQL 似乎没问题,但它不起作用。无论如何,你说得对,我不必使用 EndsWith。
  • 是的,我承认这有点奇怪,但由于(在大桌子上)性能受到巨大影响,我自己永远不会使用它。你也能接受答案吗?
猜你喜欢
  • 1970-01-01
  • 2015-09-07
  • 2013-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-07
  • 2015-10-11
相关资源
最近更新 更多