Monorepo/Modules.EDMIAPI/DatabaseWithFallback.vb
Jonathan Jenne bcbfba37b2 EDMI: Add 3-tier database access in DatabaseWithFallback, add client config,
EDMI Service: Version 2.4.0.0
EDMI: API: Version 1.4.0.0
2022-01-14 11:49:47 +01:00

396 lines
17 KiB
VB.net

Imports DigitalData.Modules.Database
Imports DigitalData.Modules.EDMI.API
Imports DigitalData.Modules.EDMI.API.Constants
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language.Utils
Public Class DatabaseWithFallback
Private ReadOnly _Logger As Logger
Private ReadOnly _Client As Client
Private ReadOnly _ClientConfig As ConfigClientConfiguration
Private ReadOnly _DatabaseECM As MSSQLServer
Private ReadOnly _DatabaseIDB As MSSQLServer
''' <summary>
''' Options for GetDatatable
''' </summary>
Public Class GetDatatableOptions
Public ReadOnly FallbackSQL
Public ReadOnly FallbackType
''' <summary>
''' Filter expression for the cached Datatable
''' </summary>
Public Property FilterExpression As String = ""
''' <summary>
''' Columns to sort the cached Datatable by
''' </summary>
Public Property SortByColumn As String = ""
''' <summary>
''' Force the fallback, skipping the service completely
''' </summary>
Public Property ForceFallback As Boolean = False
''' <summary>
''' Connection Id to use, references TBDD_CONNECTION
''' </summary>
Public Property ConnectionId As Integer = 0
''' <summary>
''' Creates a new options object for GetDatatable options
''' </summary>
''' <param name="pFallbackSQL">SQL Command to execute as fallback</param>
''' <param name="pFallbackType">Named Database to use for the fallback SQL Command</param>
Public Sub New(pFallbackSQL As String, pFallbackType As Constants.DatabaseType)
FallbackSQL = pFallbackSQL
FallbackType = pFallbackType
End Sub
End Class
Public Sub New(LogConfig As LogConfig, Client As Client, DatabaseECM As MSSQLServer, DatabaseIDB As MSSQLServer)
_Logger = LogConfig.GetLogger()
_Client = Client
_DatabaseECM = DatabaseECM
_DatabaseIDB = DatabaseIDB
' Load client config, will throw if client is not yet connected to service
_ClientConfig = Client.TryGetClientConfig()
End Sub
Public Function GetDatatableECM(pSQL As String, Optional pConnectionId As Integer = 0) As DataTable
Return GetDatatable(New GetDatatableOptions(pSQL, Constants.DatabaseType.ECM) With {
.ConnectionId = pConnectionId
})
End Function
Public Function GetDatatableIDB(pSQL As String, Optional pConnectionId As Integer = 0) As DataTable
Return GetDatatable(New GetDatatableOptions(pSQL, Constants.DatabaseType.IDB) With {
.ConnectionId = pConnectionId
})
End Function
Public Function GetScalarValueECM(pSQL As String, Optional pConnectionId As Integer = 0) As Object
Return GetScalarValue(pSQL, Constants.DatabaseType.ECM, pForceFallback:=False, pConnectionId)
End Function
Public Function GetScalarValueIDB(pSQL As String, Optional pConnectionId As Integer = 0) As Object
Return GetScalarValue(pSQL, Constants.DatabaseType.IDB, pForceFallback:=False, pConnectionId)
End Function
Public Function ExecuteNonQueryECM(pSQL As String, Optional pConnectionId As Integer = 0) As Boolean
Return ExecuteNonQuery(pSQL, Constants.DatabaseType.ECM, pForceFallback:=False, pConnectionId)
End Function
Public Function ExecuteNonQueryIDB(pSQL As String, Optional pConnectionId As Integer = 0) As Boolean
Return ExecuteNonQuery(pSQL, Constants.DatabaseType.IDB, pForceFallback:=False, pConnectionId)
End Function
''' <summary>
''' Returns a Datatable by trying to fetch a cached version from the service, then querying the database through the service and querying the database directly as fallback.
''' </summary>
''' <param name="pDataTableName">Name of the Cached Datatable</param>
''' <param name="pOptions">Options object</param>
Public Function GetDatatable(pDataTableName As String, pOptions As GetDatatableOptions) As DataTable
Return GetDatatable(pDataTableName, pOptions.FallbackSQL, pOptions.FallbackType, pOptions.FilterExpression, pOptions.SortByColumn, pOptions.ForceFallback, pOptions.ConnectionId)
End Function
''' <summary>
''' Returns a datatable directly from the database.
''' </summary>
''' <param name="pOptions">Options object</param>
Public Function GetDatatable(pOptions As GetDatatableOptions) As DataTable
Dim oForceFallback = True
Return GetDatatable("FORCE_FALLBACK", pOptions.FallbackSQL, pOptions.FallbackType, pOptions.FilterExpression, pOptions.SortByColumn, oForceFallback, pOptions.ConnectionId)
End Function
''' <summary>
''' Returns a Datatable by trying to fetch a cached version from the service, then querying the database through the service and querying the database directly as fallback.
''' </summary>
''' <param name="pDataTableName">Name of the Cached Datatable</param>
''' <param name="pFallbackSQL">SQL Command to execute as fallback</param>
''' <param name="pFallbackType">Named Database to use for the fallback SQL Command</param>
''' <param name="pFilterExpression">Filter expression for the cached Datatable</param>
''' <param name="pSortByColumn">Columns to sort the cached Datatable by</param>
''' <param name="pForceFallback">Force the fallback, skipping the service completely</param>
''' <param name="pConnectionId">Connection Id to use, references TBDD_CONNECTION</param>
Public Function GetDatatable(pDataTableName As String, pFallbackSQL As String, pFallbackType As Constants.DatabaseType, Optional pFilterExpression As String = "", Optional pSortByColumn As String = "", Optional pForceFallback As Boolean = False, Optional pConnectionId As Integer = 0) As DataTable
Try
Dim oResult As DataTable = Nothing
Dim oTableResult As TableResult = Nothing
' If there is no client, we assume there is no service (configured)
If _Client Is Nothing Then
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
End If
' If ForceFallback flag is set, we go to database immediately
If pForceFallback Or _ClientConfig.ForceDirectDatabaseAccess Then
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
End If
' If the table is not cached, we try going through the service
If Not IsTableCached(pDataTableName) Then
Return GetDatatableFromService(pFallbackSQL, pFallbackType, pConnectionId)
End If
' If there is a proper ConnectionId, we try going through the service
If pConnectionId > 0 Then
Return GetDatatableFromService(pFallbackSQL, pFallbackType, pConnectionId)
End If
Try
oTableResult = _Client.GetDatatableByName(pDataTableName, pFilterExpression, pSortByColumn)
Catch ex As Exception
_Logger.Error(ex)
oTableResult = Nothing
End Try
If oTableResult Is Nothing OrElse oTableResult.OK = False Then
_Logger.Warn("Datatable [{0}] could not be fetched from AppServer Cache. Falling back to direct Database Access.", pDataTableName)
Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId)
Else
Return oTableResult.Table
End If
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
End Try
End Function
''' <summary>
''' Returns a Scalar Value by querying the database through the service and querying the database directly as fallback.
''' </summary>
''' <param name="pSQL">SQL Command to execute as fallback</param>
''' <param name="pDatabaseType">Named Database to use for the fallback SQL Command</param>
''' <param name="pForceFallback">Force the fallback, skipping the service completely</param>
''' <param name="pConnectionId">Connection Id to use, references TBDD_CONNECTION</param>
Public Function GetScalarValue(pSQL As String, pDatabaseType As Constants.DatabaseType, Optional pForceFallback As Boolean = False, Optional pConnectionId As Integer = 0) As DataTable
Try
Dim oResult As DataTable = Nothing
Dim oTableResult As TableResult = Nothing
' If there is no client, we assume there is no service (configured)
If _Client Is Nothing Then
Return GetScalarValueFromDatabase(pSQL, pDatabaseType, pConnectionId)
End If
' If ForceFallback flag is set, we go to database immediately
If pForceFallback Or _ClientConfig.ForceDirectDatabaseAccess Then
Return GetScalarValueFromDatabase(pSQL, pDatabaseType, pConnectionId)
End If
Return GetScalarValueFromService(pSQL, pDatabaseType, pConnectionId)
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
End Try
End Function
''' <summary>
''' Returns a Scalar Value by querying the database through the service and querying the database directly as fallback.
''' </summary>
''' <param name="pSQL">SQL Command to execute as fallback</param>
''' <param name="pDatabaseType">Named Database to use for the fallback SQL Command</param>
''' <param name="pForceFallback">Force the fallback, skipping the service completely</param>
''' <param name="pConnectionId">Connection Id to use, references TBDD_CONNECTION</param>
Public Function ExecuteNonQuery(pSQL As String, pDatabaseType As Constants.DatabaseType, Optional pForceFallback As Boolean = False, Optional pConnectionId As Integer = 0) As Boolean
Try
Dim oResult As DataTable = Nothing
Dim oTableResult As TableResult = Nothing
' If there is no client, we assume there is no service (configured)
If _Client Is Nothing Then
Return ExecuteNonQueryFromDatabase(pSQL, pDatabaseType, pConnectionId)
End If
' If ForceFallback flag is set, we go to database immediately
If pForceFallback Or _ClientConfig.ForceDirectDatabaseAccess Then
Return ExecuteNonQueryFromDatabase(pSQL, pDatabaseType, pConnectionId)
End If
Return ExecuteNonQueryFromService(pSQL, pDatabaseType, pConnectionId)
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function IsTableCached(pName As String) As Boolean
If _Client Is Nothing Then
Return False
End If
Return _Client.CachedTables.Contains(pName.ToUpper)
End Function
Private Function GetDatatableFromService(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As DataTable
Try
Dim oResult As GetDatatableResponse = Nothing
Select Case DatabaseType
Case Constants.DatabaseType.ECM
oResult = _Client.GetDatatableFromECM(pSQLCommand, pConnectionId)
Case Constants.DatabaseType.IDB
oResult = _Client.GetDatatableFromIDB(pSQLCommand, pConnectionId)
Case Else
Return GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
End Select
If oResult Is Nothing Then
Throw New ApplicationException("Unexpected server error ocurred!")
End If
If oResult.OK = False Then
Throw New ApplicationException(oResult.ErrorMessage)
End If
Return oResult.Table
Catch ex As Exception
_Logger.Warn("GetDatatableFromService failed. Falling back to direct database access.")
_Logger.Error(ex)
Return GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
End Try
End Function
Private Function GetDatatableFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As DataTable
Try
Dim oResult As ExecuteNonQueryResponse = Nothing
Select Case DatabaseType
Case Constants.DatabaseType.ECM
Return _DatabaseECM.GetDatatable(pSQLCommand)
Case Constants.DatabaseType.IDB
Return _DatabaseIDB.GetDatatable(pSQLCommand)
Case Else
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
Return _DatabaseECM.GetDatatableWithConnection(pSQLCommand, oConnectionString)
End Select
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function GetScalarValueFromService(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Object
Try
Dim oResult As GetScalarValueResponse = Nothing
Select Case DatabaseType
Case Constants.DatabaseType.ECM
oResult = _Client.GetScalarValueFromECM(pSQLCommand, pConnectionId)
Case Constants.DatabaseType.IDB
oResult = _Client.GetScalarValueFromIDB(pSQLCommand, pConnectionId)
End Select
If oResult Is Nothing Then
Throw New ApplicationException("Unexpected server error ocurred!")
End If
If oResult.OK = False Then
Throw New ApplicationException(oResult.ErrorMessage)
End If
Return oResult.Scalar
Catch ex As Exception
_Logger.Warn("GetScalarValueFromService failed. Falling back to direct database access.")
_Logger.Error(ex)
Return GetDatatableFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
End Try
End Function
Private Function GetScalarValueFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Object
Try
Select Case DatabaseType
Case Constants.DatabaseType.ECM
Return _DatabaseECM.GetScalarValue(pSQLCommand)
Case Constants.DatabaseType.IDB
Return _DatabaseIDB.GetScalarValue(pSQLCommand)
Case Else
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
Return _DatabaseECM.GetScalarValueWithConnection(pSQLCommand, oConnectionString)
End Select
Catch ex As Exception
_Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function ExecuteNonQueryFromService(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Boolean
Try
Dim oResult As ExecuteNonQueryResponse = Nothing
Select Case DatabaseType
Case Constants.DatabaseType.ECM
oResult = _Client.ExecuteNonQueryFromECM(pSQLCommand, pConnectionId)
Case Constants.DatabaseType.IDB
oResult = _Client.ExecuteNonQueryFromIDB(pSQLCommand, pConnectionId)
End Select
If oResult Is Nothing Then
Throw New ApplicationException("Unexpected server error ocurred!")
End If
If oResult.OK = False Then
Throw New ApplicationException(oResult.ErrorMessage)
End If
Return oResult.Result
Catch ex As Exception
_Logger.Warn("ExecuteNonQueryFromService failed. Falling back to direct database access.")
_Logger.Error(ex)
Return ExecuteNonQueryFromDatabase(pSQLCommand, DatabaseType, pConnectionId)
End Try
End Function
Private Function ExecuteNonQueryFromDatabase(pSQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) As Boolean
Try
Select Case DatabaseType
Case Constants.DatabaseType.ECM
Return _DatabaseECM.ExecuteNonQuery(pSQLCommand)
Case Constants.DatabaseType.IDB
Return _DatabaseIDB.ExecuteNonQuery(pSQLCommand)
Case Else
Dim oConnectionString = _DatabaseECM.Get_ConnectionStringforID(pConnectionId)
Return _DatabaseECM.ExecuteNonQueryWithConnection(pSQLCommand, oConnectionString)
End Select
Catch ex As Exception
_Logger.Error(ex)
Return False
End Try
End Function
End Class