Unterstützung für dynamische SQL-Templates hinzugefügt
Die Änderungen umfassen: - Hinzufügen von Platzhalter-Checks für SQL-Templates (`ContainsTableColumnPlaceholder`) und deren Verarbeitung. - Implementierung zeilenspezifischer Editoren (`CreateRowSpecificEditor`) basierend auf aufgelösten SQL-Templates. - Erweiterung der Editor-Logik in `GridControl.vb`, um dynamische Editoren zu unterstützen. - Modularisierung und Verbesserung der SQL-Formel-Verarbeitung (`TriggerSqlFormulasAfterExpressionUpdate`, `ExecuteSqlFormulas`). - Erweiterung der Validierung in `frmValidator.vb`, um Platzhalter in SQL-Befehlen zu prüfen. - Optimierung der Logging-Ausgaben für bessere Nachvollziehbarkeit. - Refactoring zur Verbesserung der Lesbarkeit und Konsistenz. - Erweiterung der Komponenten in `Product.wxs` (z. B. Hinzufügen von `DLLLicenseManager.dll`). - Zusätzliche Validierungen für Spaltenformeln und neue Zeilen. Diese Änderungen verbessern die Flexibilität, Stabilität und Nachvollziehbarkeit der Anwendung.
This commit is contained in:
@@ -110,26 +110,27 @@
|
||||
</Component>
|
||||
|
||||
<Component Id="DDLibs" Guid="BA2979E3-3778-48B8-B0D8-4B77825B9293">
|
||||
<File Id="LookupGrid" Name="DigitalData.Controls.LookupGrid.dll" Source="DigitalData.Controls.LookupGrid.dll"/>
|
||||
<File Id="DDSnapPanel" Name="DigitalData.Controls.SnapPanel.dll" Source="DigitalData.Controls.SnapPanel.dll"/>
|
||||
<File Id="DDCommonGUIs" Name="DigitalData.GUIs.Common.dll" Source="DigitalData.GUIs.Common.dll"/>
|
||||
<File Id="DDConfig" Name="DigitalData.Modules.Config.dll" Source="DigitalData.Modules.Config.dll"/>
|
||||
<File Id="DDLogging" Name="DigitalData.Modules.Logging.dll" Source="DigitalData.Modules.Logging.dll"/>
|
||||
<File Id="DDInterfaces" Name="DigitalData.Modules.Interfaces.dll" Source="DigitalData.Modules.Interfaces.dll"/>
|
||||
<File Id="DDBase" Name="DigitalData.Modules.Base.dll" Source="DigitalData.Modules.Base.dll"/>
|
||||
<File Id="DDFilesystem" Name="DigitalData.Modules.Filesystem.dll" Source="DigitalData.Modules.Filesystem.dll"/>
|
||||
<File Id="DDEncryption" Name="DigitalData.Modules.Encryption.dll" Source="DigitalData.Modules.Encryption.dll"/>
|
||||
<File Id="DDWindream" Name="DigitalData.Modules.Windream.dll" Source="DigitalData.Modules.Windream.dll"/>
|
||||
<File Id="DDWindows" Name="DigitalData.Modules.Windows.dll" Source="DigitalData.Modules.Windows.dll"/>
|
||||
<File Id="DDZooflow" Name="DigitalData.Modules.Zooflow.dll" Source="DigitalData.Modules.Zooflow.dll"/>
|
||||
<File Id="DDDatabase" Name="DigitalData.Modules.Database.dll" Source="DigitalData.Modules.Database.dll"/>
|
||||
<File Id="DDPatterns" Name="DigitalData.Modules.Patterns.dll" Source="DigitalData.Modules.Patterns.dll"/>
|
||||
<File Id="DDEDMIAPI" Name="DigitalData.Modules.EDMI.API.dll" Source="DigitalData.Modules.EDMI.API.dll"/>
|
||||
<File Id="DDDocumentViewer" Name="DigitalData.Controls.DocumentViewer.dll" Source="DigitalData.Controls.DocumentViewer.dll"/>
|
||||
<File Id="Messaging" Name="DigitalData.Modules.Messaging.dll" Source="DigitalData.Modules.Messaging.dll" KeyPath="no" />
|
||||
<File Id="Messaging.License" Name="MailLicense.xml" Source="MailLicense.xml" KeyPath="no" />
|
||||
<File Id="Limilabs.Mail" Name="Mail.dll" Source="Mail.dll" KeyPath="no" />
|
||||
<File Id="NLog" Name="NLog.dll" Source="NLog.dll"/>
|
||||
<File Id="LookupGrid" Name="DigitalData.Controls.LookupGrid.dll" Source="DigitalData.Controls.LookupGrid.dll"/>
|
||||
<File Id="DDSnapPanel" Name="DigitalData.Controls.SnapPanel.dll" Source="DigitalData.Controls.SnapPanel.dll"/>
|
||||
<File Id="DDCommonGUIs" Name="DigitalData.GUIs.Common.dll" Source="DigitalData.GUIs.Common.dll"/>
|
||||
<File Id="DDConfig" Name="DigitalData.Modules.Config.dll" Source="DigitalData.Modules.Config.dll"/>
|
||||
<File Id="DDLogging" Name="DigitalData.Modules.Logging.dll" Source="DigitalData.Modules.Logging.dll"/>
|
||||
<File Id="DDInterfaces" Name="DigitalData.Modules.Interfaces.dll" Source="DigitalData.Modules.Interfaces.dll"/>
|
||||
<File Id="DDBase" Name="DigitalData.Modules.Base.dll" Source="DigitalData.Modules.Base.dll"/>
|
||||
<File Id="DDFilesystem" Name="DigitalData.Modules.Filesystem.dll" Source="DigitalData.Modules.Filesystem.dll"/>
|
||||
<File Id="DDEncryption" Name="DigitalData.Modules.Encryption.dll" Source="DigitalData.Modules.Encryption.dll"/>
|
||||
<File Id="DDWindream" Name="DigitalData.Modules.Windream.dll" Source="DigitalData.Modules.Windream.dll"/>
|
||||
<File Id="DDWindows" Name="DigitalData.Modules.Windows.dll" Source="DigitalData.Modules.Windows.dll"/>
|
||||
<File Id="DDZooflow" Name="DigitalData.Modules.Zooflow.dll" Source="DigitalData.Modules.Zooflow.dll"/>
|
||||
<File Id="DDDatabase" Name="DigitalData.Modules.Database.dll" Source="DigitalData.Modules.Database.dll"/>
|
||||
<File Id="DDPatterns" Name="DigitalData.Modules.Patterns.dll" Source="DigitalData.Modules.Patterns.dll"/>
|
||||
<File Id="DDEDMIAPI" Name="DigitalData.Modules.EDMI.API.dll" Source="DigitalData.Modules.EDMI.API.dll"/>
|
||||
<File Id="DDDocumentViewer" Name="DigitalData.Controls.DocumentViewer.dll" Source="DigitalData.Controls.DocumentViewer.dll"/>
|
||||
<File Id="DDLicenseManager" Name="DLLLicenseManager.dll" Source="DLLLicenseManager.dll" KeyPath="no" />
|
||||
<File Id="Messaging" Name="DigitalData.Modules.Messaging.dll" Source="DigitalData.Modules.Messaging.dll" KeyPath="no" />
|
||||
<File Id="Messaging.License" Name="MailLicense.xml" Source="MailLicense.xml" KeyPath="no" />
|
||||
<File Id="Limilabs.Mail" Name="Mail.dll" Source="Mail.dll" KeyPath="no" />
|
||||
<File Id="NLog" Name="NLog.dll" Source="NLog.dll"/>
|
||||
</Component>
|
||||
<Component Id="RuntimeLibs" Guid="F7170744-3DB5-4275-ACCD-7F3B9BDE1D6E">
|
||||
<File Id="Newtonsoft.Json" Name="Newtonsoft.Json.dll" Source="Newtonsoft.Json.dll" KeyPath="yes" />
|
||||
|
||||
@@ -45,7 +45,9 @@ Namespace ControlCreator
|
||||
Private Class FormulaSqlDefinition
|
||||
Public Property SqlTemplate As String
|
||||
Public Property ReferencedColumns As List(Of String)
|
||||
Public Property ConnectionId As Integer
|
||||
End Class
|
||||
|
||||
''' <summary>
|
||||
''' Extrahiert alle {#TBCOL#ColumnName}-Platzhalter aus einem SQL-Template.
|
||||
''' </summary>
|
||||
@@ -218,6 +220,13 @@ Namespace ControlCreator
|
||||
Dim oComboboxDataTable As DataTable = Nothing
|
||||
Dim oColumnName As String = oRow.Item("SPALTENNAME")
|
||||
_Logger.Debug("Working on SQL for Column[{0}]...", oColumnName)
|
||||
|
||||
' *** NEU: Platzhalter-Check ***
|
||||
If ContainsTableColumnPlaceholder(oSqlCommand) Then
|
||||
_Logger.Debug("...SQL contains #TBCOL# placeholders – skipping static caching, will be resolved per row.")
|
||||
Continue For ' Überspringen – wird in CustomRowCellEdit behandelt
|
||||
End If
|
||||
|
||||
If Not clsPatterns.HasComplexPatterns(oSqlCommand) Then
|
||||
_Logger.Debug("SQL has no complex patterns!")
|
||||
'oComboboxDataTable = ClassDatabase.Return_Datatable_ConId(oSqlCommand, oConnectionId)
|
||||
@@ -562,6 +571,8 @@ Namespace ControlCreator
|
||||
If oFormulaExpression <> String.Empty AndAlso oFormulaSql <> String.Empty Then
|
||||
_Logger.Warn("[ConfigureViewColumnsCurrency] Column [{0}] has BOTH FORMULA_EXPRESSION and FORMULA_SQL – treating as EXPRESSION only.", oCol.FieldName)
|
||||
oFormulaSql = String.Empty
|
||||
ElseIf oFormulaSql <> String.Empty Then
|
||||
_Logger.Debug("[ConfigureViewColumnsCurrency] Column [{0}] is a SQL formula column: {1}", oCol.FieldName, oFormulaSql)
|
||||
End If
|
||||
|
||||
' Spalte ist eine Formel-Spalte (Expression ODER SQL) → nur DisplayFormat, kein ColumnEdit
|
||||
@@ -669,10 +680,10 @@ Namespace ControlCreator
|
||||
For Each r As DataRow In pColumnTable.Rows
|
||||
Dim oColName = r.Item("SPALTENNAME").ToString()
|
||||
Dim oExpr = ObjectEx.NotNull(r.Item("FORMULA_EXPRESSION"), String.Empty).ToString()
|
||||
Dim oSql = ObjectEx.NotNull(r.Item("FORMULA_SQL"), String.Empty).ToString()
|
||||
Dim oSql_FORMULA = ObjectEx.NotNull(r.Item("FORMULA_SQL"), String.Empty).ToString()
|
||||
|
||||
' *** VALIDIERUNG: Beides gleichzeitig ist nicht erlaubt ***
|
||||
If oExpr <> String.Empty AndAlso oSql <> String.Empty Then
|
||||
If oExpr <> String.Empty AndAlso oSql_FORMULA <> String.Empty Then
|
||||
_Logger.Warn("⚠️ Column [{0}] has BOTH FORMULA_EXPRESSION and FORMULA_SQL – this is not allowed! FORMULA_SQL will be ignored.", oColName)
|
||||
MsgBox(String.Format(
|
||||
"Die Spalte '{0}' enthält sowohl eine FORMULA_EXPRESSION als auch eine FORMULA_SQL." & vbCrLf &
|
||||
@@ -680,22 +691,23 @@ Namespace ControlCreator
|
||||
"FORMULA_SQL wird ignoriert. Bitte korrigieren Sie die Konfiguration im Tabellen-Designer.",
|
||||
oColName), MsgBoxStyle.Exclamation, "Ungültige Spalten-Konfiguration")
|
||||
' FORMULA_EXPRESSION hat Vorrang → SQL ignorieren
|
||||
oSql = String.Empty
|
||||
oSql_FORMULA = String.Empty
|
||||
End If
|
||||
|
||||
If oExpr <> String.Empty Then
|
||||
_FormulaColumnNames.Add(oColName)
|
||||
_Logger.Debug("[ConfigureViewEvents] Column [{0}] registered as FORMULA_EXPRESSION column.", oColName)
|
||||
ElseIf oSql <> String.Empty Then
|
||||
ElseIf oSql_FORMULA <> String.Empty Then
|
||||
Dim oConnectionId As Integer = r.ItemEx("CONNECTION_ID", 0)
|
||||
_FormulaSqlColumns(oColName) = New FormulaSqlDefinition() With {
|
||||
.SqlTemplate = oSql,
|
||||
.ReferencedColumns = GetReferencedSqlColumnNames(oSql)
|
||||
}
|
||||
.SqlTemplate = oSql_FORMULA,
|
||||
.ReferencedColumns = GetReferencedSqlColumnNames(oSql_FORMULA),
|
||||
.ConnectionId = oConnectionId ' *** Hier speichern ***
|
||||
}
|
||||
' SQL-Spalten auch in _FormulaColumnNames aufnehmen → Editor-Blockade + ReadOnly
|
||||
_FormulaColumnNames.Add(oColName)
|
||||
_Logger.Debug("[ConfigureViewEvents] Column [{0}] registered as FORMULA_SQL column. ReferencedColumns=[{1}]",
|
||||
oColName, String.Join(", ", GetReferencedSqlColumnNames(oSql)))
|
||||
oColName, String.Join(", ", GetReferencedSqlColumnNames(oSql_FORMULA)))
|
||||
End If
|
||||
Next
|
||||
|
||||
@@ -797,6 +809,8 @@ Namespace ControlCreator
|
||||
For Each oRow As DataRow In pColumnTable.Rows
|
||||
Dim oColumnName As String = oRow.Item("SPALTENNAME").ToString()
|
||||
If oColumnName <> e.Column.FieldName Then Continue For
|
||||
Dim oSqlCommand As String = oRow.ItemEx("SQL_COMMAND", "")
|
||||
Dim oConnectionId As Integer = oRow.ItemEx("CONNECTION_ID", 1)
|
||||
|
||||
Dim oEditorExists = GridTables_TestEditorExistsByControlAndColumn(pControlId, oColumnName)
|
||||
|
||||
@@ -958,31 +972,73 @@ Namespace ControlCreator
|
||||
AddHandler pControl.LostFocus, AddressOf Control_LostFocus
|
||||
|
||||
AddHandler pGridView.ShowingEditor,
|
||||
Sub(sender As Object, e As CancelEventArgs)
|
||||
Try
|
||||
Dim oView As GridView = TryCast(sender, GridView)
|
||||
If oView Is Nothing Then Return
|
||||
Sub(sender As Object, e As CancelEventArgs)
|
||||
Try
|
||||
Dim oView As GridView = TryCast(sender, GridView)
|
||||
If oView Is Nothing Then Return
|
||||
|
||||
_Logger.Debug("Showing editor.")
|
||||
_Logger.Debug("Showing editor.")
|
||||
|
||||
' Formel-Spalten dürfen keinen Editor öffnen (gilt für EXPRESSION UND SQL)
|
||||
If oView.FocusedColumn IsNot Nothing Then
|
||||
Dim oFieldName As String = oView.FocusedColumn.FieldName
|
||||
If _FormulaColumnNames.Contains(oFieldName) Then
|
||||
_Logger.Debug("Cancelling editor – column [{0}] is a formula column (Expression or SQL).", oFieldName)
|
||||
e.Cancel = True
|
||||
Return
|
||||
' Formel-Spalten dürfen keinen Editor öffnen
|
||||
If oView.FocusedColumn IsNot Nothing Then
|
||||
Dim oFieldName As String = oView.FocusedColumn.FieldName
|
||||
If _FormulaColumnNames.Contains(oFieldName) Then
|
||||
_Logger.Debug("Cancelling editor – column [{0}] is a formula column (Expression or SQL).", oFieldName)
|
||||
e.Cancel = True
|
||||
Return
|
||||
End If
|
||||
End If
|
||||
|
||||
' *** NEU: Row-specific Editor für #TBCOL# Platzhalter ***
|
||||
If oView.FocusedColumn IsNot Nothing Then
|
||||
Dim oFocusedColumnName As String = oView.FocusedColumn.FieldName
|
||||
Dim oRowHandle As Integer = oView.FocusedRowHandle
|
||||
|
||||
' Spalten-Metadata aus pColumnTable holen
|
||||
Dim oColumnData As DataRow = pColumnTable.
|
||||
Select($"SPALTENNAME = '{oFocusedColumnName}'").
|
||||
FirstOrDefault()
|
||||
|
||||
If oColumnData IsNot Nothing Then
|
||||
Dim oSqlCommand As String = oColumnData.ItemEx("SQL_COMMAND", "")
|
||||
Dim oConnectionId As Integer = oColumnData.ItemEx("CONNECTION_ID", 1)
|
||||
|
||||
' Prüfen ob SQL Platzhalter enthält
|
||||
If oSqlCommand <> "" AndAlso ContainsTableColumnPlaceholder(oSqlCommand) Then
|
||||
_Logger.Debug("[ShowingEditor] Column [{0}] has SQL with #TBCOL# placeholders – creating row-specific editor", oFocusedColumnName)
|
||||
|
||||
' Platzhalter ersetzen mit aktuellen Zeilenwerten
|
||||
Dim resolvedSql As String = ResolveSqlTemplate(oSqlCommand, oView, oRowHandle)
|
||||
|
||||
' Editor mit aufgelöstem SQL laden
|
||||
Dim oRowSpecificEditor = CreateRowSpecificEditor(
|
||||
oFocusedColumnName,
|
||||
resolvedSql,
|
||||
oConnectionId,
|
||||
oColumnData.ItemEx("ADVANCED_LOOKUP", False))
|
||||
|
||||
If oRowSpecificEditor IsNot Nothing Then
|
||||
' Editor temporär zur Spalte hinzufügen
|
||||
oView.FocusedColumn.ColumnEdit = oRowSpecificEditor
|
||||
_Logger.Debug("[ShowingEditor] Row-specific editor assigned for [{0}]", oFocusedColumnName)
|
||||
Else
|
||||
_Logger.Warn("[ShowingEditor] Failed to create row-specific editor for [{0}] – cancelling edit", oFocusedColumnName)
|
||||
e.Cancel = True
|
||||
Return
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
|
||||
If oView.IsNewItemRow(oView.FocusedRowHandle) AndAlso Not newRowModified Then
|
||||
_Logger.Debug("Adding new row.")
|
||||
oView.AddNewRow()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
_Logger.Error(ex)
|
||||
End Try
|
||||
End Sub
|
||||
' BESTEHENDER CODE: NewItemRow-Handling
|
||||
If oView.IsNewItemRow(oView.FocusedRowHandle) AndAlso Not newRowModified Then
|
||||
_Logger.Debug("Adding new row.")
|
||||
oView.AddNewRow()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
_Logger.Error(ex)
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
AddHandler pGridView.FocusedColumnChanged,
|
||||
Sub(sender As Object, e As FocusedColumnChangedEventArgs)
|
||||
@@ -1054,6 +1110,8 @@ Namespace ControlCreator
|
||||
_Logger.Debug("[FormulaRefresh] FALLBACK DisplayText for [{0}]: [{1}]",
|
||||
oFormulaColumnName, oView.GetRowCellDisplayText(oRowHandle, oGridColumn))
|
||||
Next
|
||||
' Dies fängt den Fall ab, dass eine SQL-Spalte eine Expression-Spalte referenziert
|
||||
TriggerSqlFormulasAfterExpressionUpdate(oView, oRowHandle, oFormulaColumnsToRefresh)
|
||||
Catch ex As Exception
|
||||
_Logger.Error(ex)
|
||||
End Try
|
||||
@@ -1146,6 +1204,224 @@ Namespace ControlCreator
|
||||
End Try
|
||||
End Sub
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' Prüft, ob ein SQL-Command Tabellen-Spalten-Platzhalter ({#TBCOL#...}) enthält.
|
||||
''' </summary>
|
||||
Private Function ContainsTableColumnPlaceholder(sqlCommand As String) As Boolean
|
||||
If String.IsNullOrWhiteSpace(sqlCommand) Then Return False
|
||||
Return sqlCommand.IndexOf("{#TBCOL#", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
End Function
|
||||
''' <summary>
|
||||
''' Erstellt einen zeilenspezifischen Editor (Combobox/Lookup) basierend auf aufgelöstem SQL.
|
||||
''' Wird verwendet, wenn SQL_COMMAND Platzhalter wie {#TBCOL#...} enthält.
|
||||
''' </summary>
|
||||
Private Function CreateRowSpecificEditor(
|
||||
columnName As String,
|
||||
resolvedSql As String,
|
||||
connectionId As Integer,
|
||||
isAdvancedLookup As Boolean) As RepositoryItem
|
||||
|
||||
Try
|
||||
_Logger.Debug("[CreateRowSpecificEditor] Executing SQL for column [{0}]: {1}", columnName, resolvedSql)
|
||||
|
||||
' SQL ausführen
|
||||
Dim oDataTable As DataTable = DatabaseFallback.GetDatatable(
|
||||
New GetDatatableOptions(resolvedSql, DatabaseType.ECM) With {
|
||||
.ConnectionId = connectionId
|
||||
})
|
||||
|
||||
If oDataTable Is Nothing OrElse oDataTable.Rows.Count = 0 Then
|
||||
_Logger.Warn("[CreateRowSpecificEditor] No data returned for column [{0}]", columnName)
|
||||
Return Nothing
|
||||
End If
|
||||
|
||||
_Logger.Debug("[CreateRowSpecificEditor] Retrieved {0} rows for column [{1}]", oDataTable.Rows.Count, columnName)
|
||||
|
||||
' Editor erstellen (analog zu GridTables_GetRepositoryItemForColumn)
|
||||
If isAdvancedLookup Then
|
||||
Dim oEditor = New RepositoryItemLookupControl3 With {
|
||||
.DisplayMember = oDataTable.Columns(0).ColumnName,
|
||||
.ValueMember = oDataTable.Columns(0).ColumnName,
|
||||
.DataSource = oDataTable
|
||||
}
|
||||
Return oEditor
|
||||
Else
|
||||
Dim oEditor = New RepositoryItemComboBox()
|
||||
Dim oItems As New List(Of String)
|
||||
|
||||
AddHandler oEditor.Validating,
|
||||
Sub(_sender As ComboBoxEdit, _e As CancelEventArgs)
|
||||
If oItems.Contains(_sender.EditValue) Then
|
||||
_e.Cancel = False
|
||||
Else
|
||||
_e.Cancel = True
|
||||
End If
|
||||
End Sub
|
||||
|
||||
For Each oRow2 As DataRow In oDataTable.Rows
|
||||
Dim oValue = oRow2.Item(0).ToString()
|
||||
Try
|
||||
If oRow2.ItemArray.Length > 1 Then
|
||||
oValue &= $" | {oRow2.Item(1)}"
|
||||
End If
|
||||
Catch ex As Exception
|
||||
End Try
|
||||
|
||||
oEditor.Items.Add(oValue)
|
||||
oItems.Add(oValue)
|
||||
Next
|
||||
|
||||
Return oEditor
|
||||
End If
|
||||
|
||||
Catch ex As Exception
|
||||
_Logger.Error("[CreateRowSpecificEditor] Failed to create editor for column [{0}]: {1}", columnName, ex.Message)
|
||||
_Logger.Error(ex)
|
||||
Return Nothing
|
||||
End Try
|
||||
End Function
|
||||
''' <summary>
|
||||
''' Triggert SQL-Formeln, die Expression-Spalten referenzieren (z.B. Gesamt referenziert Brutto).
|
||||
''' Wird aufgerufen NACHDEM Expression-Spalten aktualisiert wurden.
|
||||
''' </summary>
|
||||
Private Sub TriggerSqlFormulasAfterExpressionUpdate(
|
||||
pView As GridView,
|
||||
pColumnTable As DataTable,
|
||||
pRowHandle As Integer,
|
||||
pUpdatedExpressionColumns As List(Of String))
|
||||
|
||||
If pUpdatedExpressionColumns.Count = 0 Then Return
|
||||
|
||||
' Finde alle SQL-Formeln, die eine der aktualisierten Expression-Spalten referenzieren
|
||||
Dim oSqlColumnsToRefresh As New List(Of String)
|
||||
For Each kvp In _FormulaSqlColumns
|
||||
For Each updatedExprCol In pUpdatedExpressionColumns
|
||||
If kvp.Value.ReferencedColumns.Any(
|
||||
Function(col) String.Equals(col, updatedExprCol, StringComparison.OrdinalIgnoreCase)) Then
|
||||
|
||||
If Not oSqlColumnsToRefresh.Contains(kvp.Key) Then
|
||||
oSqlColumnsToRefresh.Add(kvp.Key)
|
||||
End If
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
Next
|
||||
|
||||
If oSqlColumnsToRefresh.Count > 0 Then
|
||||
_Logger.Debug("[FormulaSql] Expression columns [{0}] trigger SQL refresh for: [{1}]",
|
||||
String.Join(", ", pUpdatedExpressionColumns),
|
||||
String.Join(", ", oSqlColumnsToRefresh))
|
||||
|
||||
ExecuteSqlFormulas(pView, pRowHandle, oSqlColumnsToRefresh)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Führt SQL-Formeln aus und aktualisiert die Zellwerte.
|
||||
''' Ausgelagert in separate Methode, um Code-Duplikation zu vermeiden.
|
||||
''' </summary>
|
||||
Private Sub ExecuteSqlFormulas(
|
||||
pView As GridView,
|
||||
pRowHandle As Integer,
|
||||
pSqlColumnsToRefresh As List(Of String))
|
||||
|
||||
pView.GridControl.BeginInvoke(New Action(
|
||||
Sub()
|
||||
Try
|
||||
If Not pView.IsValidRowHandle(pRowHandle) Then Return
|
||||
|
||||
For Each oSqlColumnName As String In pSqlColumnsToRefresh
|
||||
Dim oDefinition = _FormulaSqlColumns(oSqlColumnName)
|
||||
|
||||
' Prüfen ob ALLE referenzierten Spalten einen Wert haben
|
||||
Dim allValuesPresent As Boolean = True
|
||||
For Each refCol In oDefinition.ReferencedColumns
|
||||
Dim cellVal = pView.GetRowCellValue(pRowHandle, refCol)
|
||||
If cellVal Is Nothing OrElse IsDBNull(cellVal) Then
|
||||
_Logger.Debug("[FormulaSql] Column [{0}] has NULL value – skipping SQL for [{1}]", refCol, oSqlColumnName)
|
||||
allValuesPresent = False
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
|
||||
If Not allValuesPresent Then Continue For
|
||||
|
||||
' Pattern ersetzen und SQL ausführen
|
||||
Dim resolvedSql = ResolveSqlTemplate(oDefinition.SqlTemplate, pView, pRowHandle)
|
||||
_Logger.Debug("[FormulaSql] Executing SQL for [{0}]: [{1}]", oSqlColumnName, resolvedSql)
|
||||
|
||||
Try
|
||||
' *** VEREINFACHT: ConnectionId direkt aus Definition ***
|
||||
Dim oConnectionId As Integer = oDefinition.ConnectionId
|
||||
_Logger.Debug("[FormulaSql] Using ConnectionId [{0}] for column [{1}]", oConnectionId, oSqlColumnName)
|
||||
|
||||
Dim oResultTable As DataTable = DatabaseFallback.GetDatatable(
|
||||
New GetDatatableOptions(resolvedSql, DatabaseType.ECM) With {
|
||||
.ConnectionId = oConnectionId
|
||||
})
|
||||
|
||||
If oResultTable IsNot Nothing AndAlso oResultTable.Rows.Count > 0 Then
|
||||
Dim oResult = oResultTable.Rows(0).Item(0)
|
||||
_Logger.Debug("[FormulaSql] Result for [{0}]: [{1}]", oSqlColumnName, oResult)
|
||||
|
||||
_isRefreshingFormula = True
|
||||
Try
|
||||
pView.SetRowCellValue(pRowHandle, oSqlColumnName,
|
||||
If(oResult Is Nothing OrElse IsDBNull(oResult), DBNull.Value, oResult))
|
||||
pView.RefreshRowCell(pRowHandle, pView.Columns.ColumnByFieldName(oSqlColumnName))
|
||||
Finally
|
||||
_isRefreshingFormula = False
|
||||
End Try
|
||||
Else
|
||||
_Logger.Warn("[FormulaSql] No result returned for [{0}]", oSqlColumnName)
|
||||
End If
|
||||
|
||||
Catch sqlEx As Exception
|
||||
_Logger.Warn("⚠️ [FormulaSql] SQL execution failed for [{0}]: {1}", oSqlColumnName, sqlEx.Message)
|
||||
_Logger.Error(sqlEx)
|
||||
End Try
|
||||
Next
|
||||
Catch ex As Exception
|
||||
_Logger.Error(ex)
|
||||
End Try
|
||||
End Sub))
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Triggert SQL-Formeln, die Expression-Spalten referenzieren (z.B. Gesamt referenziert Brutto).
|
||||
''' Wird aufgerufen NACHDEM Expression-Spalten aktualisiert wurden.
|
||||
''' </summary>
|
||||
Private Sub TriggerSqlFormulasAfterExpressionUpdate(
|
||||
pView As GridView,
|
||||
pRowHandle As Integer,
|
||||
pUpdatedExpressionColumns As List(Of String))
|
||||
|
||||
If pUpdatedExpressionColumns.Count = 0 Then Return
|
||||
|
||||
' Finde alle SQL-Formeln, die eine der aktualisierten Expression-Spalten referenzieren
|
||||
Dim oSqlColumnsToRefresh As New List(Of String)
|
||||
For Each kvp In _FormulaSqlColumns
|
||||
For Each updatedExprCol In pUpdatedExpressionColumns
|
||||
If kvp.Value.ReferencedColumns.Any(
|
||||
Function(col) String.Equals(col, updatedExprCol, StringComparison.OrdinalIgnoreCase)) Then
|
||||
|
||||
If Not oSqlColumnsToRefresh.Contains(kvp.Key) Then
|
||||
oSqlColumnsToRefresh.Add(kvp.Key)
|
||||
End If
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
Next
|
||||
|
||||
If oSqlColumnsToRefresh.Count > 0 Then
|
||||
_Logger.Debug("[FormulaSql] Expression columns [{0}] trigger SQL refresh for: [{1}]",
|
||||
String.Join(", ", pUpdatedExpressionColumns),
|
||||
String.Join(", ", oSqlColumnsToRefresh))
|
||||
|
||||
' *** pColumnTable nicht mehr nötig ***
|
||||
ExecuteSqlFormulas(pView, pRowHandle, oSqlColumnsToRefresh)
|
||||
End If
|
||||
End Sub
|
||||
Private Sub HandleInheritedColumnValue(pView As GridView, pColumnDefinition As DataTable, pArgs As CellValueChangedEventArgs)
|
||||
If pView Is Nothing OrElse pArgs Is Nothing OrElse pArgs.Column Is Nothing Then
|
||||
Return
|
||||
|
||||
@@ -5778,26 +5778,30 @@ Public Class frmValidator
|
||||
|
||||
Dim oAdvancedLookup = oRow.Item("ADVANCED_LOOKUP")
|
||||
oSqlCommand = clsPatterns.ReplaceAllValues(oSqlCommand, PanelValidatorControl, True)
|
||||
' Prüfen ob Platzhalter enthalten sind
|
||||
If Not ContainsTableColumnPlaceholder(oSqlCommand?.ToString()) Then
|
||||
Try
|
||||
Dim oDTRESULT_FOR_COLUMN As DataTable = GetCachedDatatable(oSqlCommand, oCONNID)
|
||||
|
||||
Try
|
||||
Dim oDTRESULT_FOR_COLUMN As DataTable = GetCachedDatatable(oSqlCommand, oCONNID)
|
||||
If Not IsNothing(oDTRESULT_FOR_COLUMN) Then
|
||||
MyValidationLogger.Debug($"Trying to create a DropDown(FIV) for CONTROL-ID [{oDEPENDING_CTRL_ID}] - RowCount: [{oDTRESULT_FOR_COLUMN.Rows.Count}] ")
|
||||
|
||||
If Not IsNothing(oDTRESULT_FOR_COLUMN) Then
|
||||
MyValidationLogger.Debug($"Trying to create a DropDown(FIV) for CONTROL-ID [{oDEPENDING_CTRL_ID}] - RowCount: [{oDTRESULT_FOR_COLUMN.Rows.Count}] ")
|
||||
|
||||
' Dictionary-Lookup statt Loop
|
||||
Dim oControl As Control = Nothing
|
||||
If _CachedControlsByGuid.TryGetValue(oDEPENDING_CTRL_ID, oControl) Then
|
||||
ControlCreator.GridTables_CacheDatatableForColumn(oDEPENDING_CTRL_ID, oDEPENDING_COLUMN, oSqlCommand, oCONNID, oAdvancedLookup)
|
||||
' Dictionary-Lookup statt Loop
|
||||
Dim oControl As Control = Nothing
|
||||
If _CachedControlsByGuid.TryGetValue(oDEPENDING_CTRL_ID, oControl) Then
|
||||
ControlCreator.GridTables_CacheDatatableForColumn(oDEPENDING_CTRL_ID, oDEPENDING_COLUMN, oSqlCommand, oCONNID, oAdvancedLookup)
|
||||
Else
|
||||
MyValidationLogger.Warn($"⚠️ Control mit ID {oDEPENDING_CTRL_ID} nicht gefunden!")
|
||||
End If
|
||||
Else
|
||||
MyValidationLogger.Warn($"⚠️ Control mit ID {oDEPENDING_CTRL_ID} nicht gefunden!")
|
||||
MyValidationLogger.Warn($"⚠️ FillIndexValues - oDTRESULT_FOR_COLUMN is nothing!")
|
||||
End If
|
||||
Else
|
||||
MyValidationLogger.Warn($"⚠️ FillIndexValues - oDTRESULT_FOR_COLUMN is nothing!")
|
||||
End If
|
||||
Catch ex As Exception
|
||||
MyValidationLogger.Warn($"⚠️ FillIndexValues - Unexpected error in creating Grid-Dropdown-Column [{oDEPENDING_COLUMN}] for CONTROL-ID [{oDEPENDING_CTRL_ID}]: " & ex.Message)
|
||||
End Try
|
||||
Catch ex As Exception
|
||||
MyValidationLogger.Warn($"⚠️ FillIndexValues - Unexpected error in creating Grid-Dropdown-Column [{oDEPENDING_COLUMN}] for CONTROL-ID [{oDEPENDING_CTRL_ID}]: " & ex.Message)
|
||||
End Try
|
||||
Else
|
||||
MyValidationLogger.Debug($"⚠️ FillIndexValues - SQL-Command for Grid-Dropdown-Column contains #CTRL# placeholder, skipping dropdown creation for CONTROL-ID [{oDEPENDING_CTRL_ID}] - Column [{oDEPENDING_COLUMN}]")
|
||||
End If
|
||||
Next
|
||||
Catch ex As Exception
|
||||
MyValidationLogger.Warn($"⚠️ FillIndexValues - Unexpected error in creating dropdown for Grid: " & ex.Message)
|
||||
@@ -5935,7 +5939,19 @@ Public Class frmValidator
|
||||
End If
|
||||
End Try
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' Prüft, ob ein SQL-Command Grid-Spalten-Platzhalter enthält
|
||||
''' </summary>
|
||||
''' <param name="sqlCommand">Der zu prüfende SQL-Command</param>
|
||||
''' <returns>True wenn Platzhalter enthalten sind, sonst False</returns>
|
||||
Private Function ContainsTableColumnPlaceholder(sqlCommand As String) As Boolean
|
||||
If String.IsNullOrWhiteSpace(sqlCommand) Then
|
||||
Return False
|
||||
End If
|
||||
|
||||
' Prüft auf #TBCOL# Platzhalter (case-insensitive)
|
||||
Return sqlCommand.IndexOf("#TBCOL#", StringComparison.OrdinalIgnoreCase) >= 0
|
||||
End Function
|
||||
Private Sub ApplyCurrencyMask(pTextEdit As TextEdit)
|
||||
If pTextEdit Is Nothing Then Return
|
||||
Try
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user