用于 SQL Server 和 VB.NET 应用程序的 MultipleActiveResultSets

Posted

技术标签:

【中文标题】用于 SQL Server 和 VB.NET 应用程序的 MultipleActiveResultSets【英文标题】:MultipleActiveResultSets for SQL Server and VB.NET application 【发布时间】:2021-11-10 16:30:45 【问题描述】:

我正在尝试使用 VB.NET 应用程序从 SQL Server 获取多个数据集。每次我尝试执行查询时的问题, 我收到这条消息:

无法更改属性“ConnectionString”。连接的当前状态是打开的

然后我尝试通过启用 MARS 来修复它

<connectionStrings>
    <add name="ConString" 
         providerName="System.Data.SqlClient" 
         connectionString="Data Source=my-PC;Initial Catalog=Project;Persist Security Info=True; MultipleActiveResultSets=true;User ID=user;Password=*****" />
</connectionStrings>

这是我的代码

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim obj, body
    obj = TextBox1.Text
    body = TextBox2.Text


    For Each mail In getemail()
        Send_mail(mail, obj, body, getattachment(mail))
    Next
    MsgBox("Traitement effectué")


End Sub
Function getemail() As List(Of String)

    Dim strMailTo As New List(Of String)
    Dim SQL As String = "Select EMail  FROM  [USER]  WHERE EMail Is Not NULL And MatriculeSalarie   Is Not NULL And [EMail] <> '' and EtatPaie = 3 and BulletinDematerialise = 1  "
    Dim cmd As New SqlCommand
    Dim sqLdr As SqlDataReader
    Dim dr As DataRow
    Try

        ConnServer()
        cmd.Connection = con
        cmd.CommandText = SQL
        Using sda As New SqlDataAdapter(cmd)
            Using ds As New DataTable()
                sda.Fill(ds)
                sqLdr = cmd.ExecuteReader()
                For i = 0 To ds.Rows.Count - 1
                    dr = ds.Rows(i)
                    strMailTo.Add(dr("EMail"))
                Next
            End Using
        End Using
        Return strMailTo
        sqLdr.Close()

    Catch ex As Exception
        MsgBox(ex.Message.ToString)

    End Try
    closeCon()

    Return strMailTo
End Function

Function getattachment(email) As String()
    Dim SQL As String = "Select MatriculeSalarie  FROM [USER] WHERE [EMail]='" & email & "'"
    Dim cmd As New SqlCommand
    Dim sqLdr As SqlDataReader
    ConnServer()
    cmd.Connection = con
    cmd.CommandText = SQL
    Dim mat As String
    mat = ""
    Dim Dir As String = ConfigurationManager.AppSettings("path1").ToString
    Dim file()
    sqLdr = cmd.ExecuteReader()

    While sqLdr.Read
        mat = sqLdr.GetValue(sqLdr.GetOrdinal("MatriculeSalarie"))
    End While
    file = IO.Directory.GetFiles(Dir, mat.Substring(1) & "*.pdf")
    sqLdr.Close()
    Return file
End Function

【问题讨论】:

对于这种特殊情况,您不需要 MARS。你需要的是停止重用SqlConnection对象。为每个查询创建一个新查询并在最后处理它(使用Using 语句),这就是它们的设计用途。每个SqlConnection 代表一个池连接的句柄,创建它们并不昂贵(超过第一个)。 请帮自己一个忙。如果不是更早,请立即阅读、理解并开始使用参数。您的代码对 sql 注入是开放的。 【参考方案1】:

如果您要做的只是在Catch 中显示一个消息框,请不要在数据库代码中这样做。让错误冒泡到用户界面代码,然后将Try 放在调用方法的位置。

不要声明没有 DataType 的变量。开启Option Infer的按钮代码设置objbody的类型。

Private ConStr As String = "Your connection string"

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim obj = TextBox1.Text
    Dim body = TextBox2.Text
    Dim emails As New List(Of String)
    Try
        emails = getemail()
    Catch ex As Exception
        MessageBox.Show(ex.Message.ToString, "Error retrieving email list")
        Exit Sub
    End Try
    For Each email In emails
        Try
            Send_mail(email, obj, body, getattachment(email))
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error getting attachments")
        End Try
    Next
    MessageBox.Show("Traitement effectué")
End Sub

SubFunction 使用的参数必须有一个DataType

我不知道你在这里做什么。

While sqLdr.Read
        mat = sqLdr.GetValue(sqLdr.GetOrdinal("MatriculeSalarie"))
 End While

每次迭代都会覆盖之前的 mat 值。我只能假设您只期望一个值,在这种情况下,您可以使用ExecuteScalar 来获取结果集第一行的第一列。在连接关闭之前不要对数据做任何事情。只需获取原始数据并关闭 (End Using) 连接。稍后处理数据。

始终使用参数。数据库服务器不将参数视为可执行代码。它们只是价值观。可以插入的可执行代码示例是“Drop table [USER];”参数的值所属的位置。糟糕!

Function getemail() As List(Of String)
    Dim SQL As String = "Select EMail  FROM  [USER]  
                            WHERE EMail Is Not NULL 
                            And MatriculeSalarie Is Not NULL 
                            And [EMail] <> '' 
                            And EtatPaie = 3 
                            And BulletinDematerialise = 1;"
    Dim dt As New DataTable
    Using con As New SqlConnection("Your connection string"),
            cmd As New SqlCommand(SQL, con)
        con.Open()
        Using reader = cmd.ExecuteReader
            dt.Load(reader)
        End Using
    End Using
    Dim strMailTo As New List(Of String)
    strMailTo = (From row As DataRow In dt.AsEnumerable
                 Select row.Field(Of String)(0)).ToList
    Return strMailTo
End Function


Function getattachment(email As String) As String()
    Dim SQL As String = "Select MatriculeSalarie  FROM [USER] WHERE [EMail]='" & email & "'"
    Dim mat As String
    Using con As New SqlConnection(ConStr),
            cmd As New SqlCommand(SQL, con)
        cmd.Parameters.Add("@email", SqlDbType.VarChar).Value = email
        con.Open()
        mat = cmd.ExecuteScalar().ToString()
    End Using
    Dim Dir As String = ConfigurationManager.AppSettings("path1").ToString
    'Your original code was fine, no need for searchPattern.
    'I added this so you could see if your search pattern was what you expected.
    Dim searchPattern = mat.Substring(1) & "*.pdf"
    Debug.Print(searchPattern) 'Appears in the Immediate window
    Dim file = IO.Directory.GetFiles(Dir, searchPattern)
    Return file
End Function

【讨论】:

以上是关于用于 SQL Server 和 VB.NET 应用程序的 MultipleActiveResultSets的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 vb.net 和 SQL Server 裁剪和调整图像大小

SQL Server 中的存储过程未使用 VB.Net 编码填充 ASP.Net 下拉列表

使用 C#/VB.NET 实现 SQL Server Profiler

如何在其他 PC 上发布 VB.net 应用程序,因为我的 PC 成为使用 sql server 的服务器主机

从 Sql Server 检索照片到 asp.net 和 Vb.net

VB.NET 不在 sql server 2008 express 中创建数据库