【问题标题】:LINQ SqlMethods.Like (and .Contains) failsLINQ SqlMethods.Like(和 .Contains)失败
【发布时间】:2017-03-31 00:14:18
【问题描述】:

我有一个名为Person 的类,它具有FirstNameLastNameMiddleName 的属性,并且我有一个名为oPeople 的表单范围的SortedDictionary(Of Integer, Person)。

Form_Load 上,我调用了一个加载65 人列表的方法。现在这是硬编码的,但最终我会从数据库中获取它。

加载表单后,我有一个名为txtSearchForNameTextBox 供用户输入搜索词,并让系统通过oPeople 过滤LastName 进行完全或部分匹配(不区分大小写)。

最终,我希望能够搜索 FirstName、LastName 和 MiddleName 之间的比较(如果有的话)。

此时我要做的就是循环遍历 LINQ 查询的结果并将它们输出到控制台窗口。

这是Person 类:

Public Class Person

    Private _fnm As String = String.Empty
    Public Property FirstName() As String
        Get
            Return _fnm
        End Get
        Set(ByVal value As String)
            _fnm = value.Trim
        End Set
    End Property

    Private _lnm As String = String.Empty
    Public Property LastName() As String
        Get
            Return _lnm
        End Get
        Set(ByVal value As String)
            _lnm = value.Trim
        End Set
    End Property

    Private _mnm As String = String.Empty
    Public Property MiddleName() As String
        Get
            Return _mnm
        End Get
        Set(ByVal value As String)
            _mnm = value.Trim
        End Set
     End Property

    Public Sub New()
    End Sub

    Public Sub New(ByVal firstName As String,
                   ByVal lastName As String,
                   Optional ByVal middleName As String = "")

        _fnm = firstName
        _lnm = lastName
        _mnm = middleName

    End Sub

End Class

这是我用来添加人员的方法。我要添加 65 人,但已减少代码:

Private Sub FillPeopleDictionary()

    Try

        If oPeople.Count > 0 Then oPeople.Clear()

        Dim oNewPerson As Person = Nothing

        oNewPerson = New Person("Scarlett", "Johansson")
        oPeople.Add(1, oNewPerson)

        oNewPerson = New Person("Amy", "Adams")
        oPeople.Add(2, oNewPerson)

        oNewPerson = New Person("Jessica", "Biel")
        oPeople.Add(3, oNewPerson)

    Catch ex As Exception

        MessageBox.Show(ex.Message, "Error [FillPeopleDictionary]", MessageBoxButtons.OK, MessageBoxIcon.Error)

    End Try

End Sub

这是我的 LINQ 语句,然后是用户单击按钮时调用的控制台输出:

Dim sSearchTerm As String = txtSearchForName.Text.Trim.ToLower

Dim queryResults = From person In oPeople
'Where SqlMethods.Like(person.Value.LastName.ToLower, "%" & sSearchTerm & "%")
'Where person.Value.LastName.ToLower.Contains("%" & sSearchTerm & "%")

Console.WriteLine("search term: " & sSearchTerm &
                  Environment.NewLine & Environment.NewLine &
                  "queryResults.Count: " & queryResults.Count.ToString &
                  Environment.NewLine)

For Each result In queryResults

   If Not String.IsNullOrEmpty(result.Value.MiddleName) Then

      Console.WriteLine(result.Key.ToString.PadLeft(2, "0") & ": " & result.Value.FirstName & " " & result.Value.MiddleName & " " & result.Value.LastName)

   Else

      Console.WriteLine(result.Key.ToString.PadLeft(2, "0") & ": " & result.Value.FirstName & " " & result.Value.LastName)

   End If

Next

LINQ 语句按原样工作,没有条件,因此它循环并正确列出oPeople 集合中的所有人员。

在最初的queryResults 语句下方有两个Where 子句被注释掉。这是我试图过滤的两种方式。一种方法是使用.Contains,另一种方法是使用.Like,但两者都不起作用。

如果用户输入“mar”,我希望从 65 人的列表中取回 6 人的列表(不区分大小写):

梅根·马克尔
玛戈·罗比
凯特·玛拉
玛丽·伊丽莎白·温斯特德
玛丽安·里维拉
艾米智能

现在当然是搜索FirstNameLastName。现在我只是想让LastName 工作。只有LastName 的列表只有:

梅根·马克尔
凯特·玛拉
艾米智能

谁能看到我在这里做错了什么?还是应该放弃将 LINQ 与 SortedDictionary 一起使用的想法?

【问题讨论】:

  • 为什么在普通的 NET 集合上使用SqlMethods?此外,感谢您发布 130 行 双倍行距 行,展示您如何添加 60 个人。我们大多数人会在 2 或 3 之后得到这个想法。见 minimal reproducible example
  • Plutonix - 我使用 SQLMethods 只是因为我只是想了解 LINQ 的工作原理。这是我第一次尝试使用它,所以我认为最好从我比较熟悉的东西开始(SortedDictionaries)。 Jinx88909 向我展示了 List(Of T) 是一种更好的方法。
  • SqlMethods 用于 Linq to SQL。您不需要它来了解答案中的 linq 或扩展方法

标签: vb.net linq filter contains


【解决方案1】:

更改您的 Person 类以包含 PersonId 并像 oNewPerson = New Person(1, "Scarlett", "Johansson") 一样传递它。

将 oPeople 更改为 List(Of Person),以便添加时看起来像这样 oPeople.Add(oNewPerson)

您的 LINQ 语句将如下所示:

Dim queryResults = From person In oPeople
                   Where person.FirstName.ToLower Like "*" & sSearchTerm & "*" Or
                         person.LastName.ToLower Like "*" & sSearchTerm & "*"

您还想更改其余部分,不再使用字典:

For Each result In queryResults

    If Not String.IsNullOrEmpty(result.MiddleName) Then

        Console.WriteLine(result.PersonId.ToString.PadLeft(2, CChar("0")) & ": " & result.FirstName & " " & result.MiddleName & " " & result.LastName)

    Else

        Console.WriteLine(result.PersonId.ToString.PadLeft(2, CChar("0")) & ": " & result.FirstName & " " & result.LastName)

    End If

Next

希望这会有所帮助。

【讨论】:

  • 这修复了它。当我试图了解更多关于 LINQ 的信息时,我确实有一个问题。 LINQ 不能与排序字典一起使用吗?我不反对使用 Lists(Of T) 我只是好奇。感谢您抽出宝贵时间全面解释更改内容并提供代码。非常感谢。
  • 是的,它仍然可以工作,但是感觉在类中弹出 PersonId 而不是字典会很有用,然后您可以引用属性而不是 .Key 作为 Id 或 .Value.FirstName。对我来说,它只是更干净一点。很高兴它解决了这个问题。
【解决方案2】:

您的第二次 Where 子句尝试已接近,除了 Contains 函数之外,String.Contains 不使用 SQL 使用的 % 通配符,因此您需要:

Dim queryResults =
    From person In oPeople
    Where person.Value.LastName.ToLower.Contains(sSearchTerm)

您可以使用OrElse person.Value.FirstName.ToLower.Contains(sSearchTerm) 轻松添加对FirstName 的检查。

【讨论】:

  • 感谢您的帮助。我从上面接受了 Jinx88909 的回应。我确实采纳了你对 OrElse 的建议。工作完美。感谢您的帮助。
【解决方案3】:

将您的 Linq 查询更改为如下:

Dim queryResults = From p In oPeople
                               Where p.Value.FirstName.ToLower.Contains(sSearchTerm) Or p.Value.LastName.ToLower.Contains(sSearchTerm)

【讨论】:

  • 我试过这个,但它仍然没有给我任何结果。我不确定我做错了什么。我最终选择了 Jinx88909 上面的回复。感谢您抽出宝贵时间。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-15
  • 2021-05-26
  • 1970-01-01
相关资源
最近更新 更多