Monorepo/Modules.Database/MSSQLServer.vb

455 lines
19 KiB
VB.net

Imports System.ComponentModel
Imports System.Data.Common
Imports System.Data.SqlClient
Imports DigitalData.Modules.Logging
Public Class MSSQLServer
Implements IDatabase
Public DBInitialized As Boolean = False
Public CurrentSQLConnectionString As String = ""
Public Const TIMEOUT_DEFAULT As Integer = 120
Public Const TABLE_DEFAULT As String = "DDRESULT"
Private ReadOnly _Timeout As Integer
Private ReadOnly _Logger As Logger
Public Enum TransactionMode
<Description("Use no transaction, neither internal nor external")>
NoTransaction
<Description("Use the transaction supplied in the Transaction Parameter")>
ExternalTransaction
<Description("Create an internal transaction on the fly")>
WithTransaction
End Enum
Public Sub New(LogConfig As LogConfig, ConnectionString As String, Optional Timeout As Integer = 120)
_Logger = LogConfig.GetLogger()
_Timeout = Timeout
CurrentSQLConnectionString = ConnectionString
Try
DBInitialized = TestCanConnect()
Catch ex As Exception
DBInitialized = False
_Logger.Error(ex)
End Try
End Sub
Public Sub New(LogConfig As LogConfig, Server As String, Database As String, UserId As String, Password As String, Optional Timeout As Integer = 120)
_Logger = LogConfig.GetLogger()
_Timeout = Timeout
CurrentSQLConnectionString = GetConnectionString(Server, Database, UserId, Password)
Try
DBInitialized = TestCanConnect()
Catch ex As Exception
DBInitialized = False
_Logger.Error(ex)
End Try
End Sub
Public Function GetConnectionString(Server As String, Database As String, UserId As String, Password As String) As String
Dim oConnectionStringBuilder As New SqlConnectionStringBuilder() With {
.DataSource = Server,
.InitialCatalog = Database,
.UserID = UserId,
.Password = Password
}
Return oConnectionStringBuilder.ToString
End Function
Public Function GetConnection() As SqlConnection
Try
Dim oConnection = GetSQLConnection()
oConnection.Open()
Return oConnection
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function MaybeGetTransaction(Connection As SqlConnection, Mode As TransactionMode, Transaction As SqlTransaction) As SqlTransaction
If Mode = TransactionMode.NoTransaction Then
Return Nothing
ElseIf Mode = TransactionMode.ExternalTransaction Then
Return Transaction
Else
Return Connection.BeginTransaction()
End If
End Function
Private Function MaybeCommitTransaction(Transaction As SqlTransaction, TransactionMode As TransactionMode) As Boolean
Select Case TransactionMode
Case TransactionMode.NoTransaction
Return True
Case TransactionMode.ExternalTransaction
Return True
Case TransactionMode.WithTransaction
Try
Transaction.Commit()
Return True
Catch ex As Exception
_Logger.Error(ex)
Return False
End Try
Case Else
Return True
End Select
End Function
Public Function Get_ConnectionStringforID(pConnectionId As Integer)
Dim connectionString As String = ""
Try
Dim oDTConnection As DataTable = GetDatatable($"SELECT * FROM TBDD_CONNECTION WHERE GUID = {pConnectionId}")
If oDTConnection.Rows.Count = 1 Then
Dim oRow As DataRow = oDTConnection.Rows(0)
Dim oProvider = oRow.Item("SQL_PROVIDER").ToString.ToUpper
Dim oServer = oRow.Item("SERVER")
Dim oDatabase = oRow.Item("DATENBANK")
Dim oUser = oRow.Item("USERNAME")
Dim oPassword = oRow.Item("PASSWORD")
Select Case oProvider
Case "MS-SQL"
If oUser = "WINAUTH" Then
connectionString = $"Server={oServer};Database={oDatabase};Trusted_Connection=True;"
Else
connectionString = $"Server={oServer};Database={oDatabase};User Id={oUser};Password={oPassword};"
End If
Case "Oracle"
If oRow.Item("BEMERKUNG").ToString.Contains("without tnsnames") Then
connectionString = $"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={oServer})(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME={oDatabase})));User Id={oUser};Password={oPassword};"
Else
connectionString = $"Data Source={oServer};Persist Security Info=True;User Id={oUser};Password={oPassword};Unicode=True"
End If
Case Else
_Logger.Warn("Provider {0} nicht unterstützt!", oProvider)
End Select
Else
_Logger.Info("No entry for Connection-ID: " & pConnectionId.ToString)
End If
Catch ex As Exception
_Logger.Error(ex)
_Logger.Info("Error in bei Get_ConnectionStringforID")
End Try
Return connectionString
End Function
Private Function TestCanConnect() As Boolean
Return TestCanConnect(CurrentSQLConnectionString)
End Function
Private Function TestCanConnect(ConnectionString As String) As Boolean
Try
_Logger.Debug("Testing connection to [{0}]", MaskConnectionString(ConnectionString))
Dim oConnection As New SqlConnection(ConnectionString)
oConnection.Open()
oConnection.Close()
Return True
Catch ex As Exception
_Logger.Error(ex)
Return False
End Try
End Function
Private Function TestCanConnect(Connection As SqlConnection) As Boolean
Try
If Connection Is Nothing Then
_Logger.Warn("TestCanConnect: Connection is nothing!")
Return False
End If
_Logger.Debug("Testing connection to [{0}]", MaskConnectionString(Connection.ConnectionString))
If Connection.State = ConnectionState.Closed Then
Connection.Open()
End If
Connection.Close()
Return True
Catch ex As Exception
_Logger.Error(ex)
Return False
End Try
End Function
Private Function GetSQLConnection() As SqlConnection
Return GetConnection(CurrentSQLConnectionString)
End Function
Private Function GetConnection(ConnectionString As String) As SqlConnection
Try
Dim oConnection As New SqlConnection(ConnectionString)
oConnection.Open()
Dim oMaskedConnectionString = MaskConnectionString(ConnectionString)
_Logger.Debug("The Following Connection is open: {0}", oMaskedConnectionString)
Return oConnection
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function MaskConnectionString(ConnectionString As String) As String
Try
If ConnectionString Is Nothing OrElse ConnectionString.Length = 0 Then
Throw New ArgumentNullException("ConnectionString")
End If
Dim oBuilder As New SqlConnectionStringBuilder() With {.ConnectionString = ConnectionString}
Dim oConnectionString = ConnectionString.Replace(oBuilder.Password, "XXXXX")
Return oConnectionString
Catch ex As Exception
_Logger.Error(ex)
Return "Invalid ConnectionString"
End Try
End Function
Public Function GetDatatable(SqlCommand As String) As DataTable Implements IDatabase.GetDatatable
Return GetDatatable(SqlCommand, _Timeout)
End Function
''' <summary>
''' Returns a datatable for a sql-statement
''' </summary>
''' <param name="SqlCommand">sqlcommand for datatable (select XYZ from TableORView)</param>
''' <returns>Returns a datatable</returns>
Public Function GetDatatable(SqlCommand As String, Timeout As Integer) As DataTable Implements IDatabase.GetDatatable
Using oSqlConnection = GetSQLConnection()
Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.WithTransaction, Nothing, Timeout)
End Using
End Function
Public Function GetDatatable(SqlCommand As String, Transaction As SqlTransaction) As DataTable
Using oSqlConnection = GetSQLConnection()
Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.ExternalTransaction, Transaction)
End Using
End Function
Public Async Function GetDatatableAsync(SqlCommand As String) As Task(Of DataTable)
Return Await Task.Run(Function() GetDatatable(SqlCommand, _Timeout))
End Function
Public Function GetDatatableWithConnection(SqlCommand As String, ConnectionString As String) As DataTable
Using oConnection = GetConnection(ConnectionString)
Return GetDatatableWithConnectionObject(SqlCommand, oConnection)
End Using
End Function
Public Function GetDatatableWithConnectionObject(SqlCommand As String, SqlConnection As SqlConnection,
Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional Transaction As SqlTransaction = Nothing,
Optional Timeout As Integer = 120) As DataTable
Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Dim oTable As New DataTable() With {.TableName = TABLE_DEFAULT}
Try
Dim oAdapter As New SqlDataAdapter(New SqlCommand With {
.CommandText = SqlCommand,
.Connection = SqlConnection,
.Transaction = oTransaction,
.CommandTimeout = Timeout
})
_Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", SqlCommand)
oAdapter.Fill(oTable)
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand)
Throw ex
Finally
MaybeCommitTransaction(oTransaction, TransactionMode)
End Try
Return oTable
End Function
Public Function ExecuteNonQuery(SQLCommand As String) As Boolean Implements IDatabase.ExecuteNonQuery
Using oConnection = GetSQLConnection()
Return ExecuteNonQueryWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, TIMEOUT_DEFAULT)
End Using
End Function
Public Function ExecuteNonQuery(SQLCommand As String, Timeout As Integer) As Boolean Implements IDatabase.ExecuteNonQuery
Using oConnection = GetSQLConnection()
Return ExecuteNonQueryWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, TIMEOUT_DEFAULT)
End Using
End Function
Public Function ExecuteNonQuery(SQLCommand As String, Transaction As SqlTransaction) As Boolean
Using oConnection = GetSQLConnection()
Return ExecuteNonQueryWithConnectionObject(SQLCommand, oConnection, TransactionMode.ExternalTransaction, Transaction, TIMEOUT_DEFAULT)
End Using
End Function
Public Async Function ExecuteNonQueryAsync(SQLCommand As String) As Task(Of Boolean)
Return Await Task.Run(Function() ExecuteNonQuery(SQLCommand))
End Function
Public Function ExecuteNonQueryWithConnection(pSQLCommand As String, ConnString As String) As Boolean
Using oConnection = GetConnection(ConnString)
Return ExecuteNonQueryWithConnectionObject(pSQLCommand, oConnection)
End Using
End Function
Public Function ExecuteNonQueryWithConnectionObject(SqlCommand As String, SqlConnection As SqlConnection,
Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional Transaction As SqlTransaction = Nothing,
Optional Timeout As Integer = 120) As Boolean
Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Try
Using oSQLCOmmand = SqlConnection.CreateCommand()
oSQLCOmmand.CommandText = SqlCommand
oSQLCOmmand.CommandTimeout = Timeout
oSQLCOmmand.Transaction = oTransaction
oSQLCOmmand.ExecuteNonQuery()
End Using
Return True
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand)
Return False
Finally
MaybeCommitTransaction(oTransaction, TransactionMode)
End Try
End Function
Public Function GetScalarValue(SQLQuery As String) As Object Implements IDatabase.GetScalarValue
Using oConnection = GetSQLConnection()
Return GetScalarValueWithConnectionObject(SQLQuery, oConnection)
End Using
End Function
Public Function GetScalarValue(SQLCommand As String, Timeout As Integer) As Object Implements IDatabase.GetScalarValue
Using oConnection = GetSQLConnection()
Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.WithTransaction, Nothing, Timeout)
End Using
End Function
Public Function GetScalarValue(SQLCommand As String, Transaction As SqlTransaction) As Object
Using oConnection = GetSQLConnection()
Return GetScalarValueWithConnectionObject(SQLCommand, oConnection, TransactionMode.ExternalTransaction, Transaction)
End Using
End Function
Public Async Function GetScalarValueAsync(SQLQuery As String) As Task(Of Object)
Return Await Task.Run(Function() GetScalarValue(SQLQuery, _Timeout))
End Function
Public Function GetScalarValueWithConnection(SQLCommand As String, ConnectionString As String) As Object
Using oConnection = GetConnection(ConnectionString)
Return GetScalarValueWithConnectionObject(SQLCommand, oConnection)
End Using
End Function
Public Function GetScalarValueWithConnectionObject(SqlCommand As String, SqlConnection As SqlConnection,
Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction,
Optional Transaction As SqlTransaction = Nothing,
Optional Timeout As Integer = 120) As Object
Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Dim oResult As Object = Nothing
Try
Using oSQLCOmmand = SqlConnection.CreateCommand()
oSQLCOmmand.CommandText = SqlCommand
oSQLCOmmand.CommandTimeout = Timeout
oSQLCOmmand.Transaction = oTransaction
oResult = oSQLCOmmand.ExecuteScalar()
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand)
Finally
MaybeCommitTransaction(oTransaction, TransactionMode)
End Try
Return oResult
End Function
Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String, Timeout As Integer) As Object
Try
If TestCanConnect() = False Then
Return Nothing
End If
_Logger.Debug("GetScalarValue: Running Query [{0}]", SQLCommand)
If SQLCommand.CommandText.Contains(" ") Then
SQLCommand.CommandType = CommandType.Text
Else
SQLCommand.CommandType = CommandType.StoredProcedure
End If
Using oConnection As SqlConnection = GetSQLConnection()
SQLCommand.Connection = oConnection
SQLCommand.Parameters(OutputParameter).Direction = ParameterDirection.Output
SQLCommand.CommandTimeout = Timeout
SQLCommand.ExecuteNonQuery()
oConnection.Close()
Return SQLCommand.Parameters(OutputParameter).Value
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"GetScalarValue failed SQLCommand [{SQLCommand}]")
Return Nothing
End Try
End Function
Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String) As Object
Return GetScalarValue(SQLCommand, OutputParameter, _Timeout)
End Function
''' <summary>
''' Executes the passed sql-statement in asyncmode
''' </summary>
''' <param name="SqlCommand">the sql statement</param>
''' <param name="commandtimeout">Optional Timeout</param>
''' <remarks></remarks>
Public Sub NewExecuteNonQueryAsync(SqlCommand As String, Optional commandtimeout As Integer = 120)
_Logger.Debug("NewExecuteNonQueryAsync: Running Query [{0}]", SqlCommand)
Try
Dim oCallback As New AsyncCallback(AddressOf NewExecuteNonQueryAsync_Callback)
Using oConnection As SqlConnection = GetSQLConnection()
Using oSQLCOmmand = oConnection.CreateCommand()
oSQLCOmmand.CommandText = SqlCommand
oSQLCOmmand.CommandTimeout = commandtimeout
oSQLCOmmand.BeginExecuteNonQuery(oCallback, oSQLCOmmand)
End Using
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"NewExecuteNonQueryAsync failed SQLCommand [{SqlCommand}]")
End Try
End Sub
Private Sub NewExecuteNonQueryAsync_Callback(ByVal result As IAsyncResult)
Dim command As SqlCommand = CType(result.AsyncState, SqlCommand)
Dim res = command.EndExecuteNonQuery(result)
_Logger.Info("Finished executing Async database operation: {0}", command.CommandText)
End Sub
End Class