LINQ:查询上的Foreach循环导致意外结果

本文关键字:意外 结果 循环 Foreach 查询 LINQ | 更新日期: 2023-09-27 17:51:21

所以我有这个查询,如果查询中有一个匹配的单词与名字,姓氏或电话号码之一,它应该返回一条记录:

var searchWords = searchQuery
                .Split(' ')
                .Select(x => x.Trim()
                .ToLower())
                .Where(y => !string.IsNullOrWhiteSpace(y)).ToArray();
foreach (var searchWord in searchWords)
        {
            var word = searchWord;
            someParentObjects= someParentObjects
            .Where(x => x.User.FirstName.ToLower().Contains(word) ||
            x.User.LastName.ToLower().Contains(word) ||
            x.User.CellPhone.Contains(word) 
            );
        }

不知何故包含匹配不工作,作为结果我得到零结果?为什么呢?

注意:第一部分工作得很好,我能够从searchQuery中获得修剪过的单词。

测试数据

:基本上我要做的就是根据查询过滤结果。如果查询中有任何单词与名字、姓氏或手机中的任何一个匹配,我将返回这些记录。因此,如果我在我的数据库中有一个记录,其中名字是"James",姓氏是"Brian",如果我将查询传递为"James Something",它应该返回一个记录。但它并没有回归。我没有得到任何记录。

LINQ:查询上的Foreach循环导致意外结果

用foreach循环包装linq语句通常是出错的迹象。Linq已经在为你做"循环"部分了。

var searchWords = searchQuery
                .Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries)
                .Select(x => x.Trim().ToUpper())
                .ToArray();

在这里,我们将搜索逻辑反转为使用Any()中的contains, Linq将为我们处理枚举。

var result = (from step in patientSteps
              where searchWords.Any(x => 
              step.User.FirstName.ToUpper().Contains(x) ||
              step.User.LastName.ToUpper().Contains(x) ||
              step.User.CellPhone.Contains(x) )
              select step);

您的代码实际上过滤了至少一个字段中存在的所有"searchWords"。对于多个单词,这样的过滤很可能没有返回结果。

搜索词"Bob John"和病人"John Doe"的简化版foreach:

var filtered = new[]{"John"}
 .Where(firstName => firstName.Contains("Bob"))
 .Where(firstName => firstName.Contains("John"));

虽然不完全清楚您在寻找什么,但可能在第一个非空结果上停止是一个选项:

    foreach (var searchWord in searchWords)
    {
        var word = searchWord;
        var filteredPatientSteps = patientSteps
        .Where(x => x.User.FirstName.ToLower().Contains(word) ||
        x.User.LastName.ToLower().Contains(word) ||
        x.User.CellPhone.Contains(word) 
        );
        if (filteredPatientSteps.Any())
        {
             // jump out on first match 
            patientSteps = filteredPatientSteps;
            break;
         }
    }

你在你的searchWords数组中得到"James"吗??你的代码似乎没问题。如果searchQuery包含像"James John Doe"这样的字符串,那么searchWords的第一个元素将是"James",其余的似乎没问题。我已经把它累成:

var searchQuery = "John Doe Brazil";
            var searchWords = searchQuery
                .Split(' ')
                .Select(x => x.Trim()
                    .ToLower())
                .Where(y => !string.IsNullOrWhiteSpace(y)).ToArray();
            User obj=new User()
            {
                FirstName = "Ali",
                LastName = "John"
            };
            var someParentObjects =new[]{ new Parent(){Users =obj}};

            foreach (var searchWord in searchWords)
            {
                var word = searchWord;
              var ParentObjects = someParentObjects
                .Where(x => x.Users.FirstName.ToLower().Contains(word) ||
                x.Users
                .LastName.ToLower().Contains(word) 
                );
            }

我将User和Parent设置为:

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
public class Parent
{
    public User Users { get; set; }
    public Parent() { }
}

本例中的ParentObjects返回对象Ali John。

编辑:

要在循环外使用ParentObjects,可以这样做:

List<Parent> ParentObjects=new List<Parent>();
            foreach (var searchWord in searchWords)
            {
                var word = searchWord;
               var ParentObject = someParentObjects.FirstOrDefault(x => x.Users.FirstName.ToLower().Contains(word) ||
                                                                        x.Users
                                                                            .LastName.ToLower().Contains(word));
                if(ParentObject!=null)
                ParentObjects.Add(ParentObject);
            }

ParentObjects可以在循环之外使用。

您还没有提供足够的创建复制,但是如果我填充其余部分,您现有的代码似乎可以工作。

void Main() {
    string searchQuery = "foo bar";
    IEnumerable<PatientStep> patientSteps = new PatientStep[] {
        new PatientStep("foo", "bar", "12345"),
        new PatientStep("foo", "williams", "12345"),
        new PatientStep("nancy", "bar", "12345"),
        new PatientStep("nothing", "relevant", "12345"),
    };
    var searchWords = searchQuery
                    .Split(' ')
                    .Select(x => x.Trim()
                        .ToLower())
                    .Where(y => !string.IsNullOrWhiteSpace(y)).ToArray();
    foreach (var searchWord in searchWords) {
        var word = searchWord;
        patientSteps = patientSteps.Where(
            x => x.User.FirstName.ToLower().Contains(word)
                || x.User.LastName.ToLower().Contains(word)
                || x.User.CellPhone.Contains(word)
        );
    }
    foreach (var patientStep in patientSteps) {
        Console.WriteLine(patientStep.ToString());
    }
}
class PatientStep {
    public User User { get; private set; }
    public PatientStep(string first, string last, string cell) {
        this.User = new User { FirstName = first, LastName = last, CellPhone = cell };
    }
    public override string ToString() {
        return string.Format("{0} {1}, {2}", this.User.FirstName, this.User.LastName, this.User.CellPhone);
    }
}
class User {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string CellPhone { get; set; }
}

输出如下:

foo bar, 12345