使用菜单按钮修改 LINQ 搜索词

Using Menu Buttons to modify LINQ search terms

在 VBS 2015 年,我创建了一个表单,该表单使用 LINQ 查询导入包含姓名、位置、年龄等的 CSV 文件,并使用唯一记录进行排序。数据被输入到数据网格中,然后可以通过 MenuStrip 中的 select 按钮进行过滤和排序。使用 LINQ 查询进行排序和过滤的过程非常简单;数组可以按升序或降序排序,也可以按其中一个字段排序。如果字段匹配查询,则整个记录(五个字段)显示在数据网格中。

到目前为止一切都很好,但这是我的问题:

如何同时应用两个不同的条件而不用为每个条件组合编写完整的查询?

例如,为了使我的问题更清楚,我可以使用原始查询对数组进行降序排序,但是当我 select 过滤器时,结果显示为升序。反之亦然,如果结果已使用五个字段可能性之一进行过滤,我如何将排序按钮应用于 prefiltered 结果?

我通过为每个 filter/sort 组合编写单独的查询来想出一种极其冗长且复杂的方法来执行此操作。每次按钮被 selected 时,都会使用基于 mnuButton.Checked = True/False 布尔值的 If 块评估另一个菜单的检查值,然后相应的查询是 运行并显示。

这是我在 运行 按下过滤器按钮之一时执行的代码示例。这个 sub 应该检查排序按钮之一是否已经 selected,然后,基于此,到 运行 两个查询之一 return 相同的过滤结果,就在升序或降序。

Private Sub mnuFilterEurope_Click(sender As Object, e As EventArgs) Handles mnuFilterEurope.Click

Dim memberinfo() As String = File.ReadAllLines("easterndiv_mission.txt")
Dim n = memberinfo.Count - 1
ReDim Missionaries(n) 'this is based on a structure defined outside this sub
Dim line As String
Dim data(5) As String
For i As Integer = 0 To n
  line = memberinfo(i)
  data = line.Split(","c)
  Missionaries(i).Last = data(0)
  Missionaries(i).First = data(1)
  Missionaries(i).State = data(2)
  Missionaries(i).Age = CInt(data(3))
  Missionaries(i).ServiceYears = CInt(data(4))
  Missionaries(i).Location = data(5) 'this is the field the 'filter' query will be evaluating.
Next
'if the 'ascending' button is selected, format the results in ascending order
If mnuSortAscending.Selected = True Then
  checkEurope() ' this references a sub procedure that selects the pressed button and deselects the other four in the menu.
  Dim populationQuery = From entry In Missionaries
                        Where entry.Location = "Europe"
                        Order By entry.Last
                        Select entry.Last, entry.First, entry.State, entry.Age, entry.ServiceYears, entry.Location
  If populationQuery.Count() > 0 Then 'check that results will be returned
    dgvOutput.DataSource = populationQuery.ToList
    dgvOutput.CurrentCell = Nothing
  Else
    MessageBox.Show("No results found")
    Exit Sub
  End If
Else
  'if the 'descending' button is selected, format the results in descending order
  checkEurope()
  Dim populationQuery = From entry In Missionaries
                        Where entry.Location = "Europe"
                        Order By entry.Last Descending
                        Select entry.Last, entry.First, entry.State, entry.Age, entry.ServiceYears, entry.Location
  If populationQuery.Count() > 0 Then
    dgvOutput.DataSource = populationQuery.ToList
    dgvOutput.CurrentCell = Nothing
  End If
End If
End Sub

对于一个按钮来说,这是非常长、笨重和耗时的,而且有十种不同的可能性......?我确信有更好的方法来编写可重用查询或排序 数据网格中显示的结果...而不是从原始文件中提取的结果。

由于用于对查询结果进行排序的菜单项非常常见,我确信这里有一种简化的方法可以实现我的最终目标。

提前感谢您的帮助,对于任何不清楚的地方和这个问题的 n00bishness,我提前表示歉意...我只使用 VB 几个星期。

您的目标是在 If mnuSortAscending.Selected 分支中不包含任何与应用 Order By entry.LastOrder By entry.Last Descending 无关的内容。正如您所说,这是保持代码可维护性的必要目标。所以任务是把每一个被复制的东西移动到一个地方,在 If:

之前或之后
checkEurope() ' this references a sub procedure that selects the pressed button and deselects the other four in the menu.
Dim populationQuery = From entry In Missionaries
                      Where entry.Location = "Europe"

'if the 'ascending' button is selected, format the results in ascending order
If mnuSortAscending.Selected = True Then
   populationQuery = From entry In populationQuery
                     Order By entry.Last
Else
   populationQuery = From entry In populationQuery
                     Order By entry.Last Descending
End If

populationQuery = From entry In populationQuery
                  Select entry.Last, entry.First, entry.State, entry.Age, entry.ServiceYears, entry.Location

If populationQuery.Count() > 0 Then 'check that results will be returned
  dgvOutput.DataSource = populationQuery.ToList
  dgvOutput.CurrentCell = Nothing
Else
  MessageBox.Show("No results found")
  Exit Sub
End If

有帮助吗?

如果你想更简洁,= True 是一个空操作(对于已经是布尔值的东西)所以你可以把它去掉。此外,LINQ 只是常规 VB 方法调用的语法糖。 From entry In populationQuery Order By entry.Last 等同于 populationQuery.OrderBy(Function (entry) entry.Last).

If mnuSortAscending.Selected Then
   populationQuery = populationQuery.OrderBy(Function (entry) entry.Last)
Else
   populationQuery = populationQuery.OrderByDescending(Function (entry) entry.Last)
End If

最后,您可以通过将 If 从其语句形式转换为其表达式形式(三元运算符),消除重复 populationQuery =:

来进一步减少重复
populationQuery = If(mnuSortAscending.Selected,
    populationQuery.OrderBy(Function (entry) entry.Last),
    populationQuery.OrderByDescending(Function (entry) entry.Last))