【问题标题】:How to fully simulate the behavior of a SQL Like in Linq-to-Entities如何在 Linq-to-Entities 中完全模拟 SQL Like 的行为
【发布时间】:2019-10-28 05:59:04
【问题描述】:

我希望在 Linq-to-Entities 中完全模拟 SQL Like 的行为。

我不想使用 StartsWith、EndsWith 或 Contains,当原始查询为:

t_test LIKE '%';

我也不能在 SqlFunctions 中使用 Linq-to-SQL 方法,因为我并不总是在实体上使用 SQL 环境(尤其是在使用模拟 DbContext 测试我的存储库时)。

在我的主要案例中,Entity 被插入到 Oracle SQL 数据库。

到目前为止,我已经在 Where 子句中尝试了这个 lambda(我使用 '*' 作为转义字符而不是 '%'):

x => (testName.StartsWith("*") && testName.EndsWith("*") &&
                         x.Name.Contains(testName.Replace("*", "")) ||
                         testName.StartsWith("*") &&
                         x.Name.EndsWith(testName.Replace("*", "")) ||
                         testName.EndsWith("*") &&
                         x.Name.StartsWith(testName.Replace("*", ""))))

实体在以下 Oracle SQL 查询中对此进行翻译:

SELECT 
"Extent1"."KEY" AS "KEY", 
"Extent1"."NAME" AS "NAME", 
FROM "T_NAME" "Extent1"
WHERE ((('*' LIKE '*%') AND ('*' LIKE '%*') AND (( NVL(INSTR("Extent1"."NAME", REPLACE('*', '*', '')), 0) ) > 0)));

不返回任何东西。

任何线索或帮助都会很棒。

【问题讨论】:

  • 对于没有经验的人,您能否描述一下 Oracle SQL 在查询 WHERE t_test LIKE '%' 时给出的行为,您想模拟哪些行为? Contains()在哪些方面无法模仿LIKE?这个问题纯粹是为了让 LINQ to Objects 表现得像 LINQ to Entities 以便让单元测试通过吗?
  • 我认为像 this extension 这样的东西可能会做你想做的事。
  • @StriplingWarrior:当然。 Oracle SQL 中的此查询返回整个表。 Contains() 无法模仿 LIKE,因为提供者构建的 SQL 查询(如上所示)没有转换完整的行为(当它应该返回所有内容时它什么也不返回)。但是 Contains() 在 Linq-to-Objects 上下文中工作得很好。你是对的,我需要让我的单元测试通过,这就是我不能使用 Linq-to-SQL 的原因(这也是我不能简单地使用 Regex.IsMatch 的原因)
  • 如果查询是为了返回整个表,为什么不完全省略Where 子句?
  • 我发现对于唯一目的是与数据库交互的类,拥有正确的行为(可通过 Integration 测试验证)比拥有通过 unit 的代码更重要 测试。如果代码在运行时表现不同,测试就没有真正的价值:测试可以通过并给您一种错误的安全感,然后在您实际执行时失败。

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


【解决方案1】:

我终于找到了问题。

实际上,testName.Replace("*", "") 似乎被误解了。在 Linq 之外进行处理时,构建的 SQL 查询是正确的,一切正常。

更正:

string correctName = testName.Replace("*", "");

x => (testName.StartsWith("*") && testName.EndsWith("*") &&
                         x.Name.Contains(correctName) ||
                         testName.StartsWith("*") &&
                         x.Name.EndsWith(correctName) ||
                         testName.EndsWith("*") &&
                         x.Name.StartsWith(correctName)))

由此产生的 SQL 是:

SELECT
"Extent1"."KEY" AS "KEY", 
"Extent1"."NAME" AS "NAME",
FROM "T_NAME" "Extent1"
WHERE (('*' LIKE '*%') AND ('*' LIKE '%*') AND ("Extent1"."NAME" LIKE "%%" ESCAPE '\'))

现在一切正常。

【讨论】:

  • 您是否故意只允许*s 在名称的开头和结尾?有人无法搜索“Joan”以获取“Johann”和“Jonathan”?或者这是您将其转换为 LINQ to Entities 这一事实的意外副作用?这可能是更适合使用 SQL 的情况之一。您可以将给定字符串中的“”替换为“%”,然后在带有直接 LIKE 检查的参数化查询中使用结果字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-19
相关资源
最近更新 更多