Database: Add Support for MSSQL Transactions

BREAKING CHANGE: Rename GetScalarValueConStr and ExecuteNonQueryCS
This commit is contained in:
Jonathan Jenne 2021-04-15 11:13:46 +02:00
parent 52f2394e6e
commit 37609ee918

View File

@ -1,4 +1,5 @@
Imports System.Data.Common Imports System.ComponentModel
Imports System.Data.Common
Imports System.Data.SqlClient Imports System.Data.SqlClient
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
@ -8,9 +9,21 @@ Public Class MSSQLServer
Public DBInitialized As Boolean = False Public DBInitialized As Boolean = False
Public CurrentSQLConnectionString As String = "" 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 _Timeout As Integer
Private ReadOnly _Logger As Logger 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) Public Sub New(LogConfig As LogConfig, ConnectionString As String, Optional Timeout As Integer = 120)
_Logger = LogConfig.GetLogger() _Logger = LogConfig.GetLogger()
_Timeout = Timeout _Timeout = Timeout
@ -49,6 +62,36 @@ Public Class MSSQLServer
Return oConnectionStringBuilder.ToString Return oConnectionStringBuilder.ToString
End Function 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) Public Function Get_ConnectionStringforID(pConnectionId As Integer)
Dim connectionString As String = "" Dim connectionString As String = ""
Try Try
@ -94,7 +137,7 @@ Public Class MSSQLServer
Private Function TestCanConnect(ConnectionString As String) As Boolean Private Function TestCanConnect(ConnectionString As String) As Boolean
Try Try
_Logger.Debug("Testing connection to [{0}]", ConnectionString) _Logger.Debug("Testing connection to [{0}]", MaskConnectionString(ConnectionString))
Dim oConnection As New SqlConnection(ConnectionString) Dim oConnection As New SqlConnection(ConnectionString)
oConnection.Open() oConnection.Open()
oConnection.Close() oConnection.Close()
@ -105,11 +148,28 @@ Public Class MSSQLServer
End Try End Try
End Function End Function
Private Function GetSQLConnection() As SqlConnection Private Function TestCanConnect(Connection As SqlConnection) As Boolean
Return GetSQLConnection(CurrentSQLConnectionString) 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))
Connection.Open()
Connection.Close()
Return True
Catch ex As Exception
_Logger.Error(ex)
Return False
End Try
End Function End Function
Private Function GetSQLConnection(ConnectionString As String) As SqlConnection Private Function GetSQLConnection() As SqlConnection
Return GetConnection(CurrentSQLConnectionString)
End Function
Private Function GetConnection(ConnectionString As String) As SqlConnection
Try Try
Dim oConnection As New SqlConnection(ConnectionString) Dim oConnection As New SqlConnection(ConnectionString)
oConnection.Open() oConnection.Open()
@ -136,233 +196,186 @@ Public Class MSSQLServer
End Try End Try
End Function End Function
Public Function GetDatatable(SqlCommand As String) As DataTable Implements IDatabase.GetDatatable
Return GetDatatable(SqlCommand, _Timeout)
End Function
''' <summary> ''' <summary>
''' Returns a datatable for a sql-statement ''' Returns a datatable for a sql-statement
''' </summary> ''' </summary>
''' <param name="SqlCommand">sqlcommand for datatable (select XYZ from TableORView)</param> ''' <param name="SqlCommand">sqlcommand for datatable (select XYZ from TableORView)</param>
''' <returns>Returns a datatable</returns> ''' <returns>Returns a datatable</returns>
Public Function GetDatatable(SqlCommand As String, Timeout As Integer) As DataTable Implements IDatabase.GetDatatable Public Function GetDatatable(SqlCommand As String, Timeout As Integer) As DataTable Implements IDatabase.GetDatatable
Try Using oSqlConnection = GetSQLConnection()
If TestCanConnect() = False Then Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.WithTransaction, Nothing, Timeout)
Return Nothing
End If
_Logger.Debug("GetDatatable: Running Query [{0}]", SqlCommand)
Using oConnection = GetSQLConnection()
Using oSQLCOmmand = oConnection.CreateCommand()
oSQLCOmmand.CommandText = SqlCommand
oSQLCOmmand.CommandTimeout = Timeout
Dim dt As DataTable = New DataTable()
Dim oAdapter As SqlDataAdapter = New SqlDataAdapter(oSQLCOmmand)
oAdapter.Fill(dt)
Return dt
End Using End Using
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"GetDatatable failed SQLCommand [{SqlCommand}]")
Return Nothing
End Try
End Function End Function
Public Function GetDatatable(SqlCommand As String) As DataTable Implements IDatabase.GetDatatable Public Function GetDatatable(SqlCommand As String, Transaction As SqlTransaction) As DataTable
Return GetDatatable(SqlCommand, _Timeout) Using oSqlConnection = GetSQLConnection()
Return GetDatatableWithConnectionObject(SqlCommand, oSqlConnection, TransactionMode.ExternalTransaction, Transaction)
End Using
End Function End Function
Public Async Function GetDatatableAsync(SqlCommand As String) As Task(Of DataTable) Public Async Function GetDatatableAsync(SqlCommand As String) As Task(Of DataTable)
Return Await Task.Run(Function() Return Await Task.Run(Function() GetDatatable(SqlCommand, _Timeout))
Return GetDatatable(SqlCommand, _Timeout)
End Function)
End Function End Function
Public Function GetDatatableWithConnection(SqlCommand As String, ConnectionString As String) As DataTable Public Function GetDatatableWithConnection(SqlCommand As String, ConnectionString As String) As DataTable
Try Using oConnection = GetConnection(ConnectionString)
If TestCanConnect(ConnectionString) = False Then Return GetDatatableWithConnectionObject(SqlCommand, oConnection)
Return Nothing
End If
_Logger.Debug("GetDatatableWithConnection: Running Query [{0}]", SqlCommand)
Using oConnection = GetSQLConnection(ConnectionString)
Using oSQLCOmmand = oConnection.CreateCommand()
oSQLCOmmand.CommandText = SqlCommand
oSQLCOmmand.CommandTimeout = _Timeout
Dim dt As DataTable = New DataTable()
Dim oAdapter As SqlDataAdapter = New SqlDataAdapter(oSQLCOmmand)
oAdapter.Fill(dt)
Return dt
End Using End Using
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"GetDatatableWithConnection failed with SQLCommand [{SqlCommand}] and ConnectionString [{MaskConnectionString(ConnectionString)}]")
Return Nothing
End Try
End Function End Function
Public Function GetDatatableWithConnection2(SqlCommand As String, ConnectionString As String) As DataTable Public Function GetDatatableWithConnectionObject(SqlCommand As String, SqlConnection As SqlConnection,
Try Optional TransactionMode As TransactionMode = TransactionMode.WithTransaction,
If TestCanConnect(ConnectionString) = False Then Optional Transaction As SqlTransaction = Nothing,
Optional Timeout As Integer = 120) As DataTable
If TestCanConnect(SqlConnection) = False Then
Return Nothing Return Nothing
End If End If
_Logger.Debug("GetDatatableWithConnection2: Running Query [{0}]", SqlCommand) Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Dim oTable As New DataTable() With {.TableName = TABLE_DEFAULT}
Using oConnection = GetSQLConnection(ConnectionString) Try
Using oSQLCOmmand = oConnection.CreateCommand() Dim oAdapter As New SqlDataAdapter(New SqlCommand With {
oSQLCOmmand.CommandText = SqlCommand .CommandText = SqlCommand,
oSQLCOmmand.CommandTimeout = _Timeout .Connection = SqlConnection,
.Transaction = oTransaction,
.CommandTimeout = Timeout
})
Dim oTable As DataTable = New DataTable("DD_RESULT") _Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", SqlCommand)
Using oReader As SqlDataReader = oSQLCOmmand.ExecuteReader() oAdapter.Fill(oTable)
Dim oSchemaTable As DataTable = oReader.GetSchemaTable()
For Each oRow As DataRow In oSchemaTable.Rows _Logger.Debug("GetDatatableWithConnectionObject: Running Query [{0}]", SqlCommand)
Dim oDataColumn As New DataColumn Catch ex As Exception
oDataColumn.ColumnName = oRow("ColumnName").ToString() _Logger.Error(ex)
oDataColumn.DataType = Type.GetType(oRow("DataType").ToString()) _Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand)
oTable.Columns.Add(oDataColumn) Throw ex
Next Finally
MaybeCommitTransaction(oTransaction, TransactionMode)
While (oReader.Read()) End Try
Dim oRow As DataRow = oTable.NewRow()
For index = 0 To oTable.Columns.Count - 1
oRow.Item(index) = oReader.Item(index)
Next
oTable.Rows.Add(oRow)
End While
Return oTable Return oTable
End Using
End Using
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"GetDatatableWithConnection2 failed SQLCommand [{SqlCommand}]")
Return Nothing
End Try
End Function
Public Function ExecuteNonQuery(SQLCommand As String, Timeout As Integer) As Boolean Implements IDatabase.ExecuteNonQuery
Try
If TestCanConnect() = False Then
Return Nothing
End If
_Logger.Debug("ExecuteNonQuery: Running Query [{0}]", SQLCommand)
Using oConnection = GetSQLConnection()
Using oSQLCOmmand = oConnection.CreateCommand()
oSQLCOmmand.CommandText = SQLCommand
oSQLCOmmand.CommandTimeout = Timeout
oSQLCOmmand.ExecuteNonQuery()
Return True
End Using
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"ExecuteNonQuery failed SQLCommand [{SQLCommand}]")
Return False
End Try
End Function
Public Function ExecuteNonQueryCS(pSQLCommand As String, ConnString As String, Optional pInfo As String = "")
Try
If pInfo <> "" Then
pInfo = "[" & pInfo & "]"
End If
Dim SQLconnect As New SqlClient.SqlConnection
Dim SQLcommand As SqlClient.SqlCommand
SQLconnect.ConnectionString = ConnString
SQLconnect.Open()
SQLcommand = SQLconnect.CreateCommand
'Update Last Created Record in Foo
SQLcommand.CommandText = pSQLCommand
_Logger.Debug("Execute_non_Query_ConStr Created: " & pSQLCommand)
SQLcommand.ExecuteNonQuery()
SQLcommand.Dispose()
SQLconnect.Close()
Return True
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"ExecuteNonQueryCS failed SQLCommand [{pSQLCommand}]")
Return False
End Try
End Function End Function
Public Function ExecuteNonQuery(SQLCommand As String) As Boolean Implements IDatabase.ExecuteNonQuery Public Function ExecuteNonQuery(SQLCommand As String) As Boolean Implements IDatabase.ExecuteNonQuery
Return ExecuteNonQuery(SQLCommand, _Timeout) 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 End Function
Public Async Function ExecuteNonQueryAsync(SQLCommand As String) As Task(Of Boolean) Public Async Function ExecuteNonQueryAsync(SQLCommand As String) As Task(Of Boolean)
Return Await Task.Run(Function() Return Await Task.Run(Function() ExecuteNonQuery(SQLCommand))
Return ExecuteNonQuery(SQLCommand, _Timeout) End Function
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
If TestCanConnect(SqlConnection) = False Then
Return False
End If
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 End Function
Public Function GetScalarValue(SQLCommand As String, Timeout As Integer) As Object Implements IDatabase.GetScalarValue Public Function GetScalarValue(SQLCommand As String, Timeout As Integer) As Object Implements IDatabase.GetScalarValue
Try 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
If TestCanConnect() = False Then If TestCanConnect() = False Then
Return Nothing Return Nothing
End If End If
_Logger.Debug("GetScalarValue: Running Query [{0}]", SQLCommand) Dim oTransaction As SqlTransaction = MaybeGetTransaction(SqlConnection, TransactionMode, Transaction)
Dim oResult As Object = Nothing
Using oConnection As SqlConnection = GetSQLConnection()
Using oSQLCOmmand = oConnection.CreateCommand()
oSQLCOmmand.CommandText = SQLCommand
oSQLCOmmand.CommandTimeout = Timeout
Dim oResult As Object = oSQLCOmmand.ExecuteScalar()
Return oResult
End Using
End Using
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"GetScalarValue failed SQLCommand [{SQLCommand}]")
Return Nothing
End Try
End Function
Public Function GetScalarValue(SQLQuery As String) As Object Implements IDatabase.GetScalarValue
Return GetScalarValue(SQLQuery, _Timeout)
End Function
Public Async Function GetScalarValueAsync(SQLQuery As String) As Task(Of Object)
Return Await Task.Run(Function()
Return GetScalarValue(SQLQuery, _Timeout)
End Function)
End Function
Public Function GetScalarValueWithConnection(SQLCommand As String, ConnectionString As String) As Object
Try Try
If TestCanConnect(ConnectionString) = False Then Using oSQLCOmmand = SqlConnection.CreateCommand()
Return Nothing oSQLCOmmand.CommandText = SqlCommand
End If oSQLCOmmand.CommandTimeout = Timeout
oSQLCOmmand.Transaction = oTransaction
_Logger.Debug("GetScalarValue: Running Query [{0}]", SQLCommand) oResult = oSQLCOmmand.ExecuteScalar()
Using oConnection As SqlConnection = GetSQLConnection(ConnectionString)
Using oSQLCOmmand = oConnection.CreateCommand()
oSQLCOmmand.CommandText = SQLCommand
oSQLCOmmand.CommandTimeout = _Timeout
Dim oResult As Object = oSQLCOmmand.ExecuteScalar()
Return oResult
End Using
End Using End Using
Catch ex As Exception Catch ex As Exception
_Logger.Error(ex) _Logger.Error(ex)
_Logger.Warn($"GetScalarValueWithConnection failed SQLCommand [{SQLCommand}]") _Logger.Warn("GetDatatableWithConnectionObject: Error in GetDatatableWithConnection while executing command: [{0}]", SqlCommand)
Return Nothing Finally
MaybeCommitTransaction(oTransaction, TransactionMode)
End Try End Try
Return oResult
End Function End Function
Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String, Timeout As Integer) As Object Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String, Timeout As Integer) As Object
@ -396,30 +409,6 @@ Public Class MSSQLServer
Return Nothing Return Nothing
End Try End Try
End Function End Function
Public Function GetScalarValueConStr(pSQLCommand As String, ConString As String, Optional pInfo As String = "")
Dim result
Try
If pInfo <> "" Then
pInfo = "[" & pInfo & "]"
End If
Dim SQLconnect As New SqlClient.SqlConnection
Dim SQLcommand As SqlClient.SqlCommand
SQLconnect.ConnectionString = ConString
SQLconnect.Open()
SQLcommand = SQLconnect.CreateCommand
'Update Last Created Record in Foo
SQLcommand.CommandText = pSQLCommand
_Logger.Debug("Execute_Scalar_ConStr Scalar: " & pSQLCommand)
result = SQLcommand.ExecuteScalar()
SQLcommand.Dispose()
SQLconnect.Close()
Return result
Catch ex As Exception
_Logger.Error(ex)
_Logger.Warn($"GetScalarValueConStr failed SQLCommand [{pSQLCommand}]")
Return Nothing
End Try
End Function
Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String) As Object Public Function GetScalarValue(SQLCommand As SqlCommand, OutputParameter As String) As Object
Return GetScalarValue(SQLCommand, OutputParameter, _Timeout) Return GetScalarValue(SQLCommand, OutputParameter, _Timeout)