Я пытаюсь создать функцию, которая проверяет, установлен ли флажок, и если да, то возвращает новый 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
(Nothing
в VB), когда вы пытаетесь его прочитать. Подумайте о логике того, что вы делаете... Вы пытаетесь проверить If ExtLogCheckB.Checked = True
пока строится сам класс, что равно еще до того, как пользователь увидит форму. Флажок не будет установлен или даже не будет установлен до того, как форма будет построена. Вам нужно переосмыслить то, чего вы пытаетесь достичь.
хм, хорошо, имеет смысл ... Моя проблема в том, что у меня есть 2 разных IP-адреса для моего сервера базы данных, и в зависимости от этого, если я локальный в здании, используйте один IP-адрес, и если я работаю удаленно, чем другой IP-адрес. Итак, в моей программе я создаю строку подключения, а затем, когда я запускаю некоторые запросы, я открываю и закрываю соединение (mycqlconn). Поэтому я хотел добавить флажок, и если я работаю удаленно, чтобы быть в состоянии использовать другой IP-адрес, но для того же соединения (mysqlconn).
Может быть, есть другой, лучший способ, который вы можете придумать?
Я предполагаю, что в этом случае вам нужно будет создать свое SQL-соединение после показа формы пользователю, а не раньше. Какие бы данные ни извлекал ваш код только для отображения формы, они не могут зависеть от пользовательского ввода из формы. (Конечно, если вы не извлекаете данные только для того, чтобы показать форму, то зачем создавать SQL-соединение сразу после загрузки формы?)
Вы правы на 100%... Dim mysqlconn As MySqlConnection = LoginIP() просто нужен в форме и все. Спасибо, чувак
Решением вашей проблемы может быть создание свойства, которое определяет, какую строку подключения следует вернуть и к которой осуществляется доступ в кнопке (или ссылке или любом другом следующем элементе пользовательского интерфейса, который пользователь должен вызвать для продолжения).
Но также не компилируйте строки подключения в свой код, пожалуйста. Откройте свойства проекта, Настройки и добавьте туда две строки с двумя строками подключения, например.
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 в форме гнезда, чтобы я мог также использовать там ConnectionString?
На ваш дополнительный вопрос:
Вы можете добавить в свой проект модуль с именем 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 properties
, Application
и снимите флажок [ ] Enable Application Framework
. Сняв флажок, выберите StartUp
(наш недавно добавленный модуль) как Startup Object
.
Также убедитесь, что параметры компиляции установлены на
Option explicit = On
, Option strict = On
и Option 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
Я извиняюсь перед всеми, я знаю, что теперь это стало скорее учебным пособием, чем простым ответом на вопрос. Я обещаю исправиться.
Последний совет: код компилируется, но в остальном не тестируется.
Спасибо за усилия, я проверю этот вариант. Молодец :-)
Offtopic: Кто-нибудь знает способ подсветки синтаксиса (цвета) для работы с фрагментами кода VB.NET?
Возможный дубликат Что такое NullReferenceException и как его исправить?