背景
我有一个表只包含一列:名称.
比如说只有四排
| 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的列表是正确的.
SELECT "Extent1"."Name" AS "Name" FROM "USER"."Table" "Extent1" WHERE (( NVL(INSTR(REVERSE(:p__linq__0),REVERSE("Extent1"."Name")),0) ) = 1)
我已经尝试用“a@test2.com”替换:p__linq__0并在sqlDeveloper中运行查询,结果是正确的.
更多信息
如果我将EndsWith()更改为Contains(),问题就会消失.这是生成的sql for Contains()
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 Release 3
解决方法
这条线关系到我,是使用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(不区分大小写)