VB.NET - 处理带有可选参数的复杂 SQL 查询的最佳实践

问题描述

在我的应用程序中,用户应该可以选择浏览客户下的订单 - 并且应该可以对搜索应用多个过滤器。这意味着我需要一个动态 sql 查询,其中可以应用可变数量的参数。 在标准的 WinForms 应用程序中,处理此问题的最佳方法是什么?

到目前为止,我一直在使用 TableAdapters 和存储过程,但据我所知,我不能将它们与可选参数一起使用。因此,例如,如果用户想要查看所有客户订单,这没问题。但也应该可以说例如“显示过去 2 周内下的所有订单,并且其中至少有一个产品包含‘礼品代码’这个词”。因此日期和产品名称将是可选参数,但如果我在存储过程中将它们留空,则会出现错误

为了解决这个问题,我开始使用 sqlCommands 和参数在一个单独的类中构建我自己的查询。我根据传递给函数的参数为​​每个命令动态生成 commandText,然后将参数添加sqlCommand,执行它并循环遍历 sqlDataReader 以构建我将返回到我的程序的项目列表。 例如(简化):

Dim cmd As New sqlCommand With {.Connection = con}
cmd.commandText = "SELECT o.id,o.customer_name,o.date,p.productName FROM orders o JOIN order_positions p ON o.id = p.order_id WHERE o.date >= @pDate"
cmd.Parameters.Add("@pDate",sqlDbType.DateTime).Value = searchDate
Dim reader As sqlDataReader = cmd.ExecuteReader()
Dim lstOrderItems As New List(Of OrderdisplayItem)
while reader.read
  dim orderId as Integer = reader.Item(0)
  dim customerName as String = reader.Item(1)
  dim date as Date = reader.Item(2)
  dim productName as String = reader.Item(3)
  lstOrderItems.add(New OrderdisplayItem With{.id = orderId,.customerName = customerName,.date = date,.productName = productName})
End While
return lstOrderItems 

现在显然这只是为了展示我是如何进行的。实际上,我必须创建额外的循环,因为一个订单可能包含一个或多个产品等。

我的问题是:这是处理这个问题的正确方法吗?感觉整个班级都会变得非常大,因为我还有其他查询,例如查找发票、商店销售等 - 对于每个查询,我都必须编写这些阅读器循环,如果稍有改动,我将不得不再次修改我的数据库中的事情发生了变化。 在 Visual Studio tableAdapters 中真的无法处理这个问题吗?

解决方法

这意味着我需要一个动态 SQL 查询,其中可以应用可变数量的参数。

不,不是。您可以使用带有一组参数的单个查询,如果您像这样构造 SQL,则只需为要忽略的那些参数提供 NULL:

SELECT *
FROM MyTable
WHERE (@Column1 IS NULL OR Column1 = @Column1)
AND (@Column2 IS NULL OR Column2 = @Column2)

您的 VB 代码可能如下所示:

Using connection As New SqlConnection("connection string here"),command As New SqlCommand(query,connection)
    command.Parameters.Add("@Column1",SqlDbType.VarChar,50).Value = If(TextBox1.TextLength = 0,CObj(DBNull.Value),TextBox1.Text)
    command.Parameters.Add("@Column2",50).Value = If(TextBox2.TextLength = 0,TextBox2.Text)

    '...
End Using

当您为参数提供 NULL 时,它有效地匹配每条记录并且该参数被有效地忽略。您可以使用任意数量的参数和您喜欢的任何数据类型来执行此操作。