【问题标题】:Function to return a mysqlconnection返回mysql连接的函数
【发布时间】:2019-06-20 11:16:51
【问题描述】:

我正在尝试创建一个函数来检查是否选中了复选框,如果是,则返回新的 MySqlConnection,否则返回不同 MySqlConnection 的值。其实应该很简单,但对我来说没有办法。

当我在没有 IF 语句的情况下执行此操作,并且只返回一个值(连接)时,它可以工作:

    Dim mysqlconn As MySqlConnection = LoginIP()

    Public Function LoginIP() As MySqlConnection
        Return New MySqlConnection("server=100.XX.XX.XX; userid=idname; password=idpass; database=my_db")
     End Function

但这实际上是我需要做的,检查并返回连接:

   Dim mysqlconn As MySqlConnection = LoginIP()

    Public Function LoginIP() As MySqlConnection
        If ExtLogCheckB.Checked = True Then
        Return New MySqlConnection("server=100.XX.XX.XX; userid=idname; password=idpass; database=my_db")
        Else
        Return New MySqlConnection("server=200.XX.XX.XX; userid=idname; password=idpass; database=my_db")
        End If
    End Function

当我这样做时,会出现以下错误: System.InvalidOperationException: '创建表单时出错。有关详细信息,请参阅 Exception.InnerException。错误是:对象引用未设置为对象的实例。'

内部异常: NullReferenceException: 对象引用未设置为对象的实例。

【问题讨论】:

  • 这与MySQLConnection 无关。当您尝试阅读时,ExtLogCheckB 属性为 null(VB 中为 Nothing)。考虑一下您正在做的事情的逻辑...您尝试检查If ExtLogCheckB.Checked = True在构造类本身时,这是在用户甚至看到表单之前。在构建表单之前,复选框不会被选中,甚至不会存在。您需要重新考虑您要完成的工作。
  • hmm 好的有道理...我的问题是我的数据库服务器有 2 个不同的 IP 地址,如果我在建筑物中是本地的,则取决于它,如果我是工作远程比 oder IP 地址。所以在我的程序中我创建了连接字符串,然后当我运行一些查询时,我打开和关闭连接(mycqlconn)。所以我想添加一个复选框,如果我正在远程工作,则可以使用 oder IP 地址但用于相同的连接(mysqlconn)。
  • 也许还有另一种更好的方法让你想出来?
  • 我想在这种情况下,您需要在向用户显示表单之后创建 SQL 连接,而不是之前。无论您的代码为显示表单而获取的任何数据都不能依赖于表单中的用户输入。 (当然,如果您不只是为了显示表单而获取数据,那么为什么首先在表单加载时立即创建 SQL 连接?)

标签: mysql vb.net


【解决方案1】:

对于您的后续问题:

您可以将一个名为 StartUp.vb 的模块添加到您的项目中,如下所示:

Imports System
Imports System.Diagnostics
Imports System.Windows.Forms
Imports MySql.Data.MySqlClient

Module StartUp

    'Private Fields
    <DebuggerBrowsable(DebuggerBrowsableState.Never)>
    Private _LoginDetails As LoginDetails

    'Main entry point

    Public Sub Main(args As String())
        'Standard initialization, copied from a C# project
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        'Start login screen
        Dim myLoginDetails As LoginDetails = Nothing
        Using myLoginForm As New LoginForm()
            myLoginForm.ShowDialog()
            myLoginDetails = myLoginForm.LoginDetails
        End Using
        'Assign details
        If (myLoginDetails Is Nothing) Then
            Environment.ExitCode = -1 'Login cancelled
            Application.Exit()
        End If
        LoginDetails = myLoginDetails
        'Start main application
        Application.Run(New MainForm())
    End Sub

    'Public Properties

    Public Property LoginDetails As LoginDetails
        Get
            Return _LoginDetails
        End Get
        Private Set(value As LoginDetails)
            _LoginDetails = value
        End Set
    End Property

    Public ReadOnly Property FooDB As MySqlConnection
        Get
            Return LoginDetails?.FooDB
        End Get
    End Property

End Module

然后打开project propertiesApplication 并取消选中复选框[ ] Enable Application Framework。取消选中复选框后,选择StartUp(我们新添加的模块)作为Startup Object

还要确保编译选项设置为 Option explicit = OnOption strict = OnOption infer = On

然后您可能想要添加一个名为 LoginDetails.vb 的类,其中包含您需要的登录详细信息,包括具有实际数据库连接的属性。

Imports System
Imports System.Data
Imports System.Diagnostics
Imports MySql.Data.MySqlClient

Public Class LoginDetails

    'Private Fields

    <ThreadStatic>
    <DebuggerBrowsable(DebuggerBrowsableState.Never)>
    Private _OpenConnection As MySqlConnection

    'Constructors

    Public Sub New(extendedLogging As Boolean, userName As String, password As String)
        Dim myRawConnectionString As String = If(extendedLogging, My.Settings.TestDB, My.Settings.ProdDB)
        Dim myBuilder As New MySqlConnectionStringBuilder(myRawConnectionString)
        myBuilder.UserID = userName
        myBuilder.Password = password
        myBuilder.Pooling = False
        If (extendedLogging) Then
            myBuilder.UsePerformanceMonitor = True
            myBuilder.UseUsageAdvisor = True
        End If
        ConnectionString = myBuilder.ToString()
        Me.UserName = userName
        Me.DatabaseName = myBuilder.Database
        Me.ServerName = myBuilder.Server
    End Sub

    'Public Properties

    Public ReadOnly Property UserName As String

    Public ReadOnly Property DatabaseName As String

    Public ReadOnly Property ServerName As String

    Public ReadOnly Property ExtendedLogging As Boolean

    ''' <summary>Returns an open connection to the FooDB or throws an exception if not possible.</summary>
    Public ReadOnly Property FooDB As MySqlConnection
        Get
            'Return from cache
            Dim myResult As MySqlConnection = _OpenConnection
            If (myResult IsNot Nothing) Then
                'Return open conneciton
                If (myResult.State = ConnectionState.Open) Then Return myResult
                'Try to open it
                Try
                    myResult.Open()
                    If (myResult.State = ConnectionState.Open) Then Return myResult
                Catch
                End Try
                'Kill corrupted connection
                Try
                    myResult.Dispose()
                Catch
                End Try
            End If
            'Initialize and return
            Try
                myResult = New MySqlConnection(ConnectionString)
                myResult.Open()
                If (myResult.State = ConnectionState.Open) Then
                    _OpenConnection = myResult
                    Return myResult
                End If
            Catch
            End Try
            'Throw exception
            Throw New ApplicationException($"Unable to connect to database {DatabaseName} on server {ServerName}!")
        End Get
    End Property

    'Private Properties

    Private ReadOnly Property ConnectionString As String

End Class

LoginForm 背后的代码再简单不过了:

Imports System

Public Class LoginForm

    Public Property LoginDetails As LoginDetails

    Private Sub btnOkay_Click(sender As Object, e As EventArgs) Handles btnOkay.Click
        LoginDetails = New LoginDetails(ExtLogCheckB.Checked, txtLoginName.Text, txtPassword.Text)
        Close()
    End Sub

    Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        LoginDetails = Nothing
        Close()
    End Sub

End Class

一些简化数据访问的扩展方法:

Imports System
Imports System.Data
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Threading.Tasks
Imports MySql.Data.MySqlClient

'Warning: Don't use string based queries because of the danger of SQL-injection! I told you...

<Extension()>
Module ExtMySqlConnection

    <Extension()>
    Public Function ExecToString(connection As MySqlConnection, query As String) As String
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myCommand As New MySqlCommand(query, connection)
        Dim myResult As Object = myCommand.ExecuteScalar()
        Return CType(myResult, String)
    End Function

    <Extension()>
    Public Function ExecToInt32(connection As MySqlConnection, query As String) As Int32
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myCommand As New MySqlCommand(query, connection)
        Dim myResult As Object = myCommand.ExecuteScalar()
        Return CType(myResult, Int32)
    End Function

    <Extension()>
    Public Function ExecToInt32Nullable(connection As MySqlConnection, query As String) As Int32?
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myCommand As New MySqlCommand(query, connection)
        Dim myResult As Object = myCommand.ExecuteScalar()
        Return CType(myResult, Int32?)
    End Function

    <Extension()>
    Public Function ExecToDateTime(connection As MySqlConnection, query As String) As DateTime
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myCommand As New MySqlCommand(query, connection)
        Dim myResult As Object = myCommand.ExecuteScalar()
        Return CType(myResult, DateTime)
    End Function

    <Extension()>
    Public Function ExecToDateTimeNullable(connection As MySqlConnection, query As String) As DateTime?
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myCommand As New MySqlCommand(query, connection)
        Dim myResult As Object = myCommand.ExecuteScalar()
        Return CType(myResult, DateTime?)
    End Function

    <Extension()>
    Public Function ExecToDataTable(connection As MySqlConnection, ByVal query As String) As DataTable
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myDataSet As DataSet = ExecToDataSet(connection, query)
        Return myDataSet.Tables(0)
    End Function

    <Extension()>
    Public Function ExecToDataSet(connection As MySqlConnection, ByVal query As String) As DataSet
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myResult As New DataSet()
        Try
            Dim myCommand As New MySqlCommand(query, connection)
            Dim cmd As New MySqlDataAdapter(myCommand)
            cmd.Fill(myResult)
        Finally
            'CloseConnection()
        End Try
        Return myResult
    End Function

    ''' <summary>Takes the connection and executes the given query on it and returns the result as a single row of type 
    ''' <see cref="DataRow" />. If the query results in 0 rows, null is returned. If the query results in multiple rows, 
    ''' an <see cref="AmbiguousMatchException" /> is thrown.</summary>
    ''' <param name="connection">The connection on which to invoke the query (a <see cref="NullReferenceException" /> is thrown if the parameter is null to simulate instance method behavior).</param>
    ''' <param name="query">The SQL statement to be executed.</param>
    ''' <returns>The according <see cref="DataRow" /> or null (or an <see cref="AmbiguousMatchException" /> may be thrown).</returns>
    <Extension()>
    Public Function ExecToDataRow(connection As MySqlConnection, ByVal query As String) As DataRow
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Return ExecToDataRow(connection, query, False)
    End Function

    ''' <summary>Takes the connection and executes the given query on it and returns the result as a single row of type 
    ''' <see cref="DataRow" />. If the query results in 0 rows, null is returned. If the query results in multiple rows, 
    ''' it depends on parameter <paramref name="ignoreAdditionalRows"/> whether the first record is returned (true) or
    ''' an <see cref="AmbiguousMatchException" /> is thrown (false).</summary>
    ''' <param name="connection">The connection on which to invoke the query (a <see cref="NullReferenceException" /> is thrown if the parameter is null to simulate instance method behavior).</param>
    ''' <param name="query">The SQL statement to be executed.</param>
    ''' <param name="ignoreAdditionalRows">Determines whether additional rows should be silently ignored if more than one rows are returnd (true) or whether an <see cref="AmbiguousMatchException" /> should be thrown (false).</param>
    ''' <returns>The according <see cref="DataRow" /> or null (or an <see cref="AmbiguousMatchException" /> may be thrown).</returns>
    <Extension()>
    Public Function ExecToDataRow(connection As MySqlConnection, ByVal query As String, ignoreAdditionalRows As Boolean) As DataRow
        'Check args
        If (connection Is Nothing) Then Throw New NullReferenceException()
        If (String.IsNullOrWhiteSpace(query)) Then Throw New ArgumentNullException(NameOf(query), "The query is null or empty!")
        'Execute query
        Dim myDataTable As DataTable = ExecToDataTable(connection, query)
        'Handle 1 or 0 records
        Select Case myDataTable.Rows.Count
            Case 1
                Return myDataTable.Rows(0)
            Case 0
                Return Nothing
        End Select
        'Determine what to do if there are more than one record
        If (Not ignoreAdditionalRows) Then
            Throw New AmbiguousMatchException()
        End If
        Return myDataTable.Rows(0)
    End Function

End Module

一个示例实体:

Imports System
Imports System.Data
Imports System.Diagnostics

<DebuggerDisplay("{DebuggerDisplayValue}")>
Public Class SampleEntity

    'Private Fields
    Private ReadOnly _Record As DataRow

    'Constructors

    Public Sub New(record As DataRow)
        If (record Is Nothing) Then Throw New ArgumentNullException(NameOf(record))
        _Record = record
    End Sub

    'Public Properties

    Public ReadOnly Property RecID As Int32
        Get
            Return _Record.Field(Of Int32)("RecID")
        End Get
    End Property

    Public ReadOnly Property LastName As String
        Get
            Return _Record.Field(Of String)("LastName")
        End Get
    End Property

    Public ReadOnly Property FirstName As String
        Get
            Return _Record.Field(Of String)("FirstName")
        End Get
    End Property

    Public ReadOnly Property FullName As String
        Get
            Return If(LastName, "") & " " & If(FirstName, "").Trim()
        End Get
    End Property

    Public ReadOnly Property EntryDate As DateTime
        Get
            Return _Record.Field(Of DateTime)("EntryDate")
        End Get
    End Property

    Public ReadOnly Property LeavingDate As DateTime?
        Get
            Return _Record.Field(Of DateTime?)("LeavingDate")
        End Get
    End Property

    Public ReadOnly Property IsActive As Boolean
        Get
            Return _Record.Field(Of Boolean)("IsActive")
        End Get
    End Property

    'Private Properties

    Private ReadOnly Property DebuggerDisplayValue As String
        Get
            Return $"{RecID}: {FullName}"
        End Get
    End Property

End Class

现在您可以非常轻松地访问应用程序中的数据表单(例如 MainForm):

Imports System.Collections.Generic
Imports System.Data

Public Class MainForm

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim myAppUsers = GetUsers()
        'Bind the users to some control
    End Sub

    Private Iterator Function GetUsers() As IEnumerable(Of SampleEntity)
        Dim myDT = FooDB.ExecToDataTable("SELECT * FROM AppUser ORDER BY LastName, FirstName")
        For Each myRecord As DataRow In myDT.Rows
            Yield New SampleEntity(myRecord)
        Next
    End Function

End Class

我向大家道歉,我知道它现在更像是一个教程,而不是一个问题的简单答案。我保证改革。

最后提示:代码可以编译,但未经测试。

【讨论】:

  • 感谢 erfort,我会测试这个选项。干得好:-)
  • Offtopic:有人知道语法高亮(颜色)在 VB.NET 代码 sn-ps 上工作的方法吗?
【解决方案2】:

您的问题的解决方案可能是创建一个属性,该属性决定要返回哪个连接字符串并在按钮(或链接或用户必须调用的任何下一个 UI 元素才能继续)中访问该字符串。

但也请不要将任何连接字符串编译到您的代码中。打开项目属性,设置,并在其中添加两行与您的两个连接字符串,例如

Name    Type                 Scope        Value
------  -------------------  -----------  ----------------------------------------------------------------
ProdDB  (Connection string)  Application  server=100.XX.XX.XX;userid=idname;password=idpass;database=my_db
TestDB  (Connection string)  Application  server=200.XX.XX.XX;userid=idname;password=idpass;database=my_db

这会将它们添加到您的 App.config 中,并允许您将来更改它们而无需重新编译您的应用程序。 (尽管如果您的连接字符串包含用户名和密码,将它们编译到可执行文件中可能会稍微安全一些。)

表单中的代码可能如下所示:

Private ReadOnly Property ConnectionString As String
    Get
        With My.Settings
            Return If(ExtLogCheckB.Checked, .TestDB, .ProdDB)
        End With
    End Get
End Property

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim myConnection As New MySqlConnection(ConnectionString)
    'Do something with it...
End Sub

【讨论】:

  • 好的,这对我来说是新事物,但它运行良好。但是我有这个问题:我的第一个表单是登录表单,在“登录过程”之后,我关闭了这个表单并打开了一个新表单(我的程序表单)。所以“复选框”信息消失了,然后“获取”过程不起作用,我怎么能以嵌套形式传递 Retunr 函数,以便我也可以在那里使用 ConnectionSrin?
猜你喜欢
  • 1970-01-01
  • 2013-03-16
  • 2016-05-12
  • 1970-01-01
  • 2015-05-08
  • 1970-01-01
  • 2019-05-21
  • 1970-01-01
  • 2011-07-22
相关资源
最近更新 更多