LINQ从字符串数组中查找一个匹配项

9

我遇到了一些困难,无法让它正常工作:

    /// <summary>
    /// Retrieve search suggestions from previous searches
    /// </summary>
    public static string[] getSearchSuggestions(int SectionID, string Query)
    {
        string[] Suggestions;
        string[] Words = Query.Split(' ');

        using (MainContext db = new MainContext())
        {
            Suggestions = (from c in db.tblSearches
                        where c.SectionID == SectionID &&
                        Words.Any(w => c.Term.Contains(w))
                        select c.Term).ToArray();
        }

        return Suggestions;
    }

我收到如下错误信息:
System.NotSupportedException: 除了 Contains 操作符之外,不能在 LINQ to SQL 查询运算符的实现中使用局部序列。
我想要返回包含Words数组中任何单词的字段c.Term的记录。同时我希望按照匹配数量的总数进行排序,但这似乎很难做到!我找到了这个MSDN。但我也无法将其与我的查询一起使用。此外,还发现了这个,但它不起作用

这个语法看起来不错。我将它移植到一些本地代码中,并能够使一个相同的查询在我的上下文中工作。(使用3.5框架) - Joel Etherton
@Joel,我用的是4框架,这个引发了下面报错的问题 :( - Tom Gullen
c.term只是一个简单的字符串值吗? - esastincy
@esas 是的,nvarchar(60)。 - Tom Gullen
1
它会是一个包含多个单词的字符串吗? - esastincy
3个回答

6

好的,在足够努力地尝试后,我意识到问题不在于 Any 或 Contains。Linq to SQL 不喜欢将本地序列(words)与 SQL 集合(db.tblSearches)组合起来。因此为了实现这一点,您需要将其拆分成两个单独的查询。

public static string[] getSearchSuggestions(int SectionID, string Query)
{
    string[] Suggestions;
    string[] Words = Query.Split(' ');

    using (MainContext db = new MainContext())
    {
        string[] all = (from c in db.tblSearches
                    where c.SectionID == SectionID
                    select c.Term).ToArray();

        Suggestions = (from a in all
                       from w in Words
                       where a.Contains(w)
                       select a).Distinct().ToArray();


    }

    return Suggestions;
}

请注意,在第二个查询中,Contains是区分大小写的,因此您可能需要添加一个不区分大小写的扩展方法或使用旧方法.ToUpper()。我在我的某个上下文中运行了这个查询,并正确返回了所有88个字符串(可能有9814个)。虽然这很麻烦,但这个问题绝对值得一加。请注意,最终答案已添加.Distinct()

非常感谢!:D 太棒了,完美运行,只是有时会返回重复项,但我认为我可以解决这个问题。此外,where a.ToLower().Contains(w.ToLower()) 似乎也使其不区分大小写。 - Tom Gullen
选择 a).Distinct().ToArray(); 以获取不同的值,结合小写是完美的答案:D 非常感谢! - Tom Gullen
@Tom Gullen:在 .ToArray() 调用之前,你可以加入一个 .Distinct() 调用来消除任何重复项。 - Joel Etherton
@Joel,在all变量之后执行.ToArray()并没有太多意义——为什么不让它保持懒加载状态,直到需要使用时再进行计算呢?根据你目前的代码示例,它将会在.ToArray()中遍历元素,然后在Suggestions中再次遍历。 - ebb
@ebb:不好意思,我刚才误读了你的评论。你可能可以避免第一个.ToArray(),并且还能提高一点性能。当我进行测试时,我试图保持类型兼容以消除可能存在的问题。 - Joel Etherton

3

首先将你的数组转换为列表

 List<string> wordList = Words.ToList();

然后,将您的linq查询更改为以下内容:
    Suggestions = (from c in db.tblSearches                           
where c.SectionID == SectionID &&                           
Words.Contains(c.Term)                           
select c.Term).ToArray();  

我想我理解了你的问题。在你原始的查询中,你使用了c.Term.Contains()... Contains是一个扩展方法,需要调用实现Enumerable的对象,所以你不能在从数据库调用返回的字段上调用它。这就是为什么另一个回答你问题的用户说你需要在Contains中翻转事物的原因,因为它永远不会让你在c.Terms上进行那个调用。

不起作用,我也将Words更改为wordList。.Contains与.Any不同,我需要它匹配找到1个或多个匹配项的记录,而Contains无法做到这一点。 - Tom Gullen

2

您需要颠倒包含子句的顺序:

        Suggestions = (from c in db.tblSearches 
                    where c.SectionID == SectionID && 
                    Words.Contains(w => c.Term) 
                    select c.Term).ToArray(); 

这个测试数据没有返回任何结果吗?这是我尝试的第一种方法。它需要找到在Words中包含1个或多个匹配项的c.Term的结果。 - Tom Gullen
顺便说一下,我正在处理这个问题:https://dev59.com/tXI-5IYBdhLWcg3woJ5I - Tom Gullen
无论如何,您必须将“Any”替换为“Contains”。请查看此问题 - jhenriquez
这个答案肯定行不通 - 说一个单词出现在一个术语中和至少有一个单词出现在一个术语中是不同的。考虑单词 = { brown, fox },术语 = 'the brown fox'。 - BrokenGlass
好的。从您最初的问题来看,上述解决了您遇到的错误,但它并没有返回您想要的结果。听起来您想要在tblSearches中的term包含数组中任何/所有单词的情况。如果您正在执行所有(And),请参见[链接](http://www.thinqlinq.com/Default/Dynamically-extending-LINQ-queryies-without-building-expression-trees.aspx)。进行或操作会更具挑战性。顺便说一句,在LINQ 2 SQL中,可以将对象数组与实体集连接,但无法将实体集与数组连接。 - Jim Wooley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接