Moo*_*ozz 10 c# linq entity-framework odp.net oracle11g
背景
我有一个只包含一列的表:名称.比方说,它只有四行
| Name |
| test1.com |
| test2.com |
| test3.com |
| test4.com |
Run Code Online (Sandbox Code Playgroud)
问题
如果我查询
var email = "a@test2.com";
Table.Where(x => email.EndsWith(x.Name));
Run Code Online (Sandbox Code Playgroud)
我会得到一个空列表.但如果我先查询所有行并计算内存中的这样
var email = "a@test2.com";
Table.ToList().Where(x => email.EndsWith(x.Name));
Run Code Online (Sandbox Code Playgroud)
我会得到一个只包含test2.com的列表,这是正确的.
为第一个查询生成的SQL是
SELECT "Extent1"."Name" AS "Name"
FROM "USER"."Table" "Extent1"
WHERE (( NVL(INSTR(REVERSE(:p__linq__0), REVERSE("Extent1"."Name")), 0) ) = 1)
Run Code Online (Sandbox Code Playgroud)
我尝试用'a@test2.com'替换:p__linq__0并在SQLDeveloper中运行查询,结果是正确的.
更多信息
如果我将EndsWith()更改为Contains(),问题就会消失.这是为Contains()生成的SQL
SELECT "Extent1"."Name" AS "Name"
FROM "USER"."Table" "Extent1"
WHERE (( NVL(INSTR(:p__linq__0, "Extent1"."Name"), 0) ) > 0)
Run Code Online (Sandbox Code Playgroud)
你知道EndsWith或REVERSE方法有什么问题吗?
环境
这句话让我很担心,也是使用 EF 的人常见的陷阱:
Table.ToList().Where(x => email.EndsWith(x.Name));
Run Code Online (Sandbox Code Playgroud)
该部分Table.ToList()是最糟糕的部分,因为这实际上会将整个表具体化到内存中,然后EndsWith在 C# 中执行。这行:
Table.Where(x => email.EndsWith(x.Name));
Run Code Online (Sandbox Code Playgroud)
我会根据一般原则警告这种方法,因为当表增长到合理大小时,它会非常慢。您可以在构造查询时从电子邮件中分离出域,从而在查询到达数据库之前完成繁重的工作:
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();
Run Code Online (Sandbox Code Playgroud)
此外,如果您需要匹配存储电子邮件的列的域名,那么我的首选方法是拆分电子邮件并将域名存储在您索引并匹配的单独列中,这将扩展并成为一个管理起来容易多了。请记住,如今数据很便宜......尤其是与不可索引的表扫描相比。
另请记住(对于这两种情况)您的数据库设置为 CI(不区分大小写)
| 归档时间: |
|
| 查看次数: |
1561 次 |
| 最近记录: |