【问题标题】:How to get all the titles matching at least one word in the titleNames in C#如何在 C# 中的 titleNames 中获取与至少一个单词匹配的所有标题
【发布时间】:2018-05-11 19:49:30
【问题描述】:

我必须使用 Entity Framework 和 Lamda 表达式获取所有 titleName 与“searchText”字符串中至少一个单词匹配的标题。当有空间时,我将 searchText 拆分并将结果存储在数组中。我正在编写以下代码,但无法获得所需的输出。

var searchTextArray = searchText.Split(' ');
var result = entities.titles.Where(x => searchTextArray.Contains(x.titleName));

假设searchText 包含“孤独管理” 字符串,那么我想获取所有标题中包含titleName 的任何单词。 在这种情况下,我应该得到 titleNames 为

的标题
Some loneliness affect all
Loneliness is painful
School Management
Proper management

...

更新 1: 上面的查询生成的 SQL 为

SELECT * FROM titles  WHERE (LOWER(titleName) IN (N'loneliness', N'management')) AND (LOWER(titleName) IS NOT NULL)

但我想生成像这样的查询

SELECT * FROM titles WHERE titleName like N'%loneliness%' or titleName like N'%management%'

我在上面的表达式中遗漏了什么?

更新 2

我从@3dGrabber 的答案中得到了预期的输出,但生成的 SQL 查询仍然比 T-SQL 中的 LIKE 运算符有点混乱。非常感谢大家。生成的 SQL 现在就像

SELECT 
    *
    FROM [dbo].[titles] AS [Extent1]
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM  (SELECT 
            N'loneliness' AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
        UNION ALL
            SELECT 
            N'management' AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
        WHERE ( CAST(CHARINDEX([UnionAll1].[C1], LOWER([Extent1].[titleName])) AS int)) > 0
    )

【问题讨论】:

  • 以上在哪些方面不适合您?
  • 这应该可以。也许你想做不区分大小写的搜索?您可以将.ToLower() 应用到searchTextx.titleName
  • @SlavenTojić 为什么添加ToArray 会有任何不同?
  • 再一次,上面的代码在什么方面不适合你?你得到什么输出?
  • lambda 中的 C# linq 表达式,包含 click here

标签: c# entity-framework-6


【解决方案1】:

不确定 EF 是否可以转换所有使用的操作,但这是我在 Linq-to-Objects 中要做的:

var searchText = "Loneliness Management";
var searchTerms = searchText.ToLower().Split(' ');

var entities = new [] 
{
    "Some loneliness affect all",
    "Loneliness is painful",
    "School Management",
    "No match here",
    "Maybe the next one?",
    "Proper management"
 };

var titles = entities.Select(t => t.ToLower());

var result = titles.Where(t => searchTerms.Any(s => t.Contains(s)));

如果您想要不区分大小写的搜索,请确保 EF 支持它,或者首先将小写的数据放入数据库中。否则你可能会遇到性能问题。

【讨论】:

    【解决方案2】:

    据我了解,您需要进行不区分大小写的搜索。你可以申请.ToLower()searchTextx.titleName

    var searchTextArray = searchText.ToLower().Split(' ');
    var result = entities.titles.Where(x => searchTextArray.Contains(x.titleName.ToLower()));
    

    更新

    我想不出办法让 EF 生成这样的查询:SELECT * FROM titles WHERE titleName like N'%loneliness%' or titleName like N'%management%'

    我认为你最好的办法是使用PredicateBuilder 来构建一个表达式,如下所示:

    var searchTextArray = searchText.Split(' ');
    
    var baseExpression = PredicateBuilder.False<TEntity>(); // TEntity - typeof your entity
    foreach(var sourceToken in searchTextArray)
    {
        var temp = sourceToken;
        baseExpression = baseExpression.Or(x => x.Body.Contains(sourceToken));
    }
    
    var result = entities.titles.Where(baseExpression).ToList();
    

    【讨论】:

      【解决方案3】:

      这不是 100% 有效,但似乎有效。

      var source = "test management".Split(" ");
      var list = new List<string> { "hello world", "world management test" };
      var result = list.Where(x => x.Split(" ").Intersect(source).Any());
      

      基本上你将你的字符串拆分成一个项目列表,然后与你的源做一个交集,看看你是否找到任何东西。

      希望这会有所帮助。

      【讨论】:

      • 问题与实体框架有关,而您在内存中构建了一个列表。 x.Split(" ").Intersect(source).Any() 在 EF linq 查询中不起作用。
      • 我构建了列表来模拟实体框架查询...tbh 如果您查询 EF 和 tolist 有相同的结果...试一试,我做到了
      • 抱歉,这段代码不起作用。甚至 .Split() 调用也是无效的,因为没有接受字符串 (MSDN) 的重载。
      猜你喜欢
      • 2016-03-21
      • 2021-07-05
      • 1970-01-01
      • 2021-09-23
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多