Verbesserung der Datenvalidierung und Fehlerbehandlung
In `ClassCockpit.vb` wurden mehrere Sicherheitsprüfungen und Normalisierungen in der Methode `CreateCockpit` hinzugefügt, einschließlich der Überprüfung auf leere Tabellen, fehlende Spalten und ungültige Primärschlüssel. Duplikate und ungültige `PARENT_ID`-Referenzen werden nun entfernt oder korrigiert. In `frmMonitor.vb` wurde die Fehlerbehandlung beim Laden von Dokumenten verbessert, einschließlich Validierung des Dateipfads und lokalisierter Fehlermeldungen. Ein neues Feld `CFG_SEQUENCE` wurde in `frmCockpitConfig.vb` hinzugefügt, und ein Aufruf zu `AppendCountsToTreeAsync()` wurde in `frmMain.vb` integriert. Neue Ressourcen- und Projektdateien (`ClassCockpit.vb`, `frmMain.aa.resx`) wurden in `taskFLOW.vbproj` hinzugefügt.
This commit is contained in:
@@ -4,6 +4,34 @@
|
||||
Try
|
||||
LOGGER.Debug("=== TreeView Data Analysis ===")
|
||||
LOGGER.Debug($"Total rows: {pDTNodes.Rows.Count}")
|
||||
|
||||
' ===== SAFETY CHECKS / NORMALISIERUNGEN =====
|
||||
If pDTNodes Is Nothing OrElse pDTNodes.Rows.Count = 0 Then
|
||||
LOGGER.Warn("CreateCockpit: pDTNodes is Nothing or empty - nothing to bind")
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
' Prüfen ob Primärschlüssel-Spalte existiert
|
||||
If Not pDTNodes.Columns.Contains("PK_CFG_COCKPIT_DEFINITION_ID") Then
|
||||
LOGGER.Error("CreateCockpit: Required column 'PK_CFG_COCKPIT_DEFINITION_ID' is missing - aborting cockpit creation")
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
' Entferne Zeilen mit NULL/ungültigem PK (können beim Binding zu Duplikat-Keys führen)
|
||||
Dim rowsWithNullPk As New List(Of DataRow)
|
||||
For Each r As DataRow In pDTNodes.Rows
|
||||
If IsDBNull(r("PK_CFG_COCKPIT_DEFINITION_ID")) Then
|
||||
rowsWithNullPk.Add(r)
|
||||
End If
|
||||
Next
|
||||
If rowsWithNullPk.Count > 0 Then
|
||||
LOGGER.Warn($"CreateCockpit: Found {rowsWithNullPk.Count} row(s) with NULL PK - removing them to avoid TreeList key errors")
|
||||
For Each r As DataRow In rowsWithNullPk
|
||||
r.Delete()
|
||||
Next
|
||||
pDTNodes.AcceptChanges()
|
||||
End If
|
||||
|
||||
' ===== NUR AKTIVE KNOTEN BEHALTEN =====
|
||||
If pDTNodes.Columns.Contains("ACTIVE") And pAdmin = False Then
|
||||
Dim oInactiveRows As DataRow() = pDTNodes.Select("ACTIVE = 0 OR ACTIVE IS NULL")
|
||||
@@ -42,6 +70,54 @@
|
||||
End If
|
||||
End If
|
||||
|
||||
' ===== NULL-PARENT_IDS NORMALISIEREN (NULL -> 0) =====
|
||||
If pDTNodes.Columns.Contains("PARENT_ID") Then
|
||||
For Each r As DataRow In pDTNodes.Rows
|
||||
If IsDBNull(r("PARENT_ID")) Then
|
||||
r("PARENT_ID") = 0
|
||||
End If
|
||||
Next
|
||||
Else
|
||||
' Falls PARENT_ID fehlt, füge Spalte hinzu und setze 0
|
||||
LOGGER.Warn("CreateCockpit: 'PARENT_ID' column missing - adding and setting to 0")
|
||||
pDTNodes.Columns.Add("PARENT_ID", GetType(Integer))
|
||||
For Each r As DataRow In pDTNodes.Rows
|
||||
r("PARENT_ID") = 0
|
||||
Next
|
||||
End If
|
||||
pDTNodes.AcceptChanges()
|
||||
|
||||
' ===== DUPLIKATE PKS ERMITTELN UND ENTFERNEN =====
|
||||
Dim dupGroups = pDTNodes.AsEnumerable().
|
||||
GroupBy(Function(r) Convert.ToInt32(r("PK_CFG_COCKPIT_DEFINITION_ID"))).
|
||||
Where(Function(g) g.Count() > 1).ToList()
|
||||
|
||||
If dupGroups.Count > 0 Then
|
||||
For Each g In dupGroups
|
||||
LOGGER.Warn($"CreateCockpit: Duplicate PK detected: {g.Key}. Keeping first occurrence, removing {g.Count() - 1} duplicate row(s).")
|
||||
Dim firstSeen As Boolean = False
|
||||
For Each rr As DataRow In g
|
||||
If Not firstSeen Then
|
||||
firstSeen = True
|
||||
Continue For
|
||||
End If
|
||||
rr.Delete()
|
||||
Next
|
||||
Next
|
||||
pDTNodes.AcceptChanges()
|
||||
End If
|
||||
|
||||
' ===== PARENT_IDs REFERENZEN PRÜFEN =====
|
||||
Dim existingKeys As New HashSet(Of Integer)(pDTNodes.AsEnumerable().Select(Function(r) Convert.ToInt32(r("PK_CFG_COCKPIT_DEFINITION_ID"))))
|
||||
For Each r As DataRow In pDTNodes.Rows
|
||||
Dim pid As Integer = Convert.ToInt32(r("PARENT_ID"))
|
||||
If pid <> 0 AndAlso Not existingKeys.Contains(pid) Then
|
||||
LOGGER.Warn($"CreateCockpit: ParentId {pid} referenced by PK {r("PK_CFG_COCKPIT_DEFINITION_ID")} does not exist - setting ParentId to 0")
|
||||
r("PARENT_ID") = 0
|
||||
End If
|
||||
Next
|
||||
pDTNodes.AcceptChanges()
|
||||
|
||||
Dim rootCount = pDTNodes.AsEnumerable().Count(Function(r) Not IsDBNull(r("PARENT_ID")) AndAlso CInt(r("PARENT_ID")) = 0)
|
||||
LOGGER.Debug($"Root nodes (PARENT_ID = 0): {rootCount}")
|
||||
|
||||
@@ -67,16 +143,6 @@
|
||||
' ===== Jetzt DataSource zuweisen =====
|
||||
myTreeView.DataSource = pDTNodes
|
||||
|
||||
'' ===== DEBUG: ImageList-Inhalt prüfen =====
|
||||
'If myTreeView.SelectImageList IsNot Nothing Then
|
||||
' LOGGER.Debug($"SelectImageList hat {myTreeView.SelectImageList.Images.Count} Bilder")
|
||||
' For i As Integer = 0 To myTreeView.SelectImageList.Images.Count - 1
|
||||
' LOGGER.Debug($" Image Index {i}: {myTreeView .SelectImageList.Images.Keys(i)}")
|
||||
' Next
|
||||
'Else
|
||||
' LOGGER.Warn("SelectImageList ist Nothing!")
|
||||
'End If
|
||||
|
||||
AddHandler myTreeView.CustomDrawNodeCell, AddressOf TreeList_Config_CustomDrawNodeCell
|
||||
|
||||
' ===== MODERNES DESIGN =====
|
||||
@@ -134,24 +200,6 @@
|
||||
LOGGER.Warn("Load_Treeview: No overview nodes (TYPE_ID=0) found - keeping default collapsed state")
|
||||
End If
|
||||
|
||||
'' ===== DETAILLIERTES LOGGING =====
|
||||
'LOGGER.Debug("=== DETAILED NODE STRUCTURE AFTER SETUP ===")
|
||||
'LOGGER.Debug($"TreeList State - AllNodesCount: {TreeList_Cockpit.AllNodesCount}, RootNodes: {TreeList_Cockpit.Nodes.Count}")
|
||||
|
||||
'Dim allNodesList As New List(Of DevExpress.XtraTreeList.Nodes.TreeListNode)
|
||||
'CollectAllNodes(TreeList_Cockpit.Nodes, allNodesList)
|
||||
|
||||
'LOGGER.Debug($"Total nodes collected recursively: {allNodesList.Count}")
|
||||
|
||||
'For Each node As DevExpress.XtraTreeList.Nodes.TreeListNode In allNodesList
|
||||
' Dim nodeId = node.GetValue("PK_CFG_COCKPIT_DEFINITION_ID")
|
||||
' Dim nodeName = node.GetValue("NAME")
|
||||
' Dim nodeParent = node.GetValue("PARENT_ID")
|
||||
' Dim level = node.Level
|
||||
' Dim parentInfo = If(node.ParentNode Is Nothing, "NULL", $"ID={node.ParentNode.GetValue("PK_CFG_COCKPIT_DEFINITION_ID")}")
|
||||
|
||||
' LOGGER.Debug($" [Level {level}] ID={nodeId}, NAME={nodeName}, PARENT_ID={nodeParent}, ParentNode={parentInfo}, HasChildren={node.HasChildren}, ChildCount={node.Nodes.Count}, IsExpanded={node.Expanded}")
|
||||
'Next
|
||||
Catch ex As Exception
|
||||
LOGGER.Error($"Error in CreateCockpit: {ex.Message}")
|
||||
End Try
|
||||
@@ -186,4 +234,4 @@
|
||||
LOGGER.Error(ex)
|
||||
End Try
|
||||
End Sub
|
||||
End Class
|
||||
End Class
|
||||
@@ -895,7 +895,8 @@ Public Class frmCockpitConfig
|
||||
' ===== SQL-FELDER IM TREEVIEW-KNOTEN AKTUALISIEREN =====
|
||||
currentNode.SetValue("SQL_QUERY", _currentCockpitDefinition.SQL_Query)
|
||||
currentNode.SetValue("SQL_QUERY_COUNT", _currentCockpitDefinition.SQL_Query_Count)
|
||||
LOGGER.Debug($"TreeView SQL fields updated - SQL_Query length: {_currentCockpitDefinition.SQL_Query.Length}, SQL_Query_Count length: {_currentCockpitDefinition.SQL_Query_Count.Length}")
|
||||
currentNode.SetValue("CFG_SEQUENCE", _currentCockpitDefinition.CFG_Sequence)
|
||||
LOGGER.Debug($"TreeView SQL fields updated - SQL_Query length: {_currentCockpitDefinition.SQL_Query.Length}, SQL_Query_Count length: {_currentCockpitDefinition.SQL_Query_Count.Length}")
|
||||
|
||||
' TreeView visuell aktualisieren
|
||||
TreeList_Cockpit.RefreshNode(currentNode)
|
||||
|
||||
@@ -564,7 +564,7 @@ Public Class frmMain
|
||||
End If
|
||||
Dim clsck As New ClassCockpit()
|
||||
clsck.CreateCockpit(oDT_STRUCTURE_NODES, TreeList_Cockpit, False)
|
||||
|
||||
AppendCountsToTreeAsync()
|
||||
Catch ex As Exception
|
||||
LOGGER.Error(ex)
|
||||
Finally
|
||||
|
||||
@@ -182,11 +182,25 @@ Public Class frmMonitor
|
||||
'_frmDocView.LoadFile(oDocPath)
|
||||
|
||||
If File.Exists(oDocPath) Then
|
||||
DocumentViewerMonitor.LoadFile_FromPath(oDocPath)
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
|
||||
DocumentViewerMonitor.Visible = True
|
||||
' DocumentViewerMonitor.RightOnlyView(USER_RIGHT_VIEW_ONLY)
|
||||
|
||||
Try
|
||||
If DocumentViewerMonitor Is Nothing Then
|
||||
LOGGER.Error("DocumentViewerMonitor is Nothing in Load_Doc")
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
|
||||
BarStaticItemInfo.Caption = "DocView not initialized"
|
||||
DocumentViewerMonitor.Visible = False
|
||||
Else
|
||||
DocumentViewerMonitor.LoadFile_FromPath(oDocPath)
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
|
||||
DocumentViewerMonitor.Visible = True
|
||||
' DocumentViewerMonitor.RightOnlyView(USER_RIGHT_VIEW_ONLY)
|
||||
End If
|
||||
Catch ex As Exception
|
||||
LOGGER.Error(ex)
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
|
||||
BarStaticItemInfo.Caption = "Error loading document"
|
||||
DocumentViewerMonitor.Visible = False
|
||||
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error in LoadDoc:")
|
||||
End Try
|
||||
Else
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
|
||||
BarStaticItemInfo.Caption = $"File is not existing or accessible!"
|
||||
@@ -459,16 +473,55 @@ Public Class frmMonitor
|
||||
End If
|
||||
|
||||
BarButtonItem3.Down = True
|
||||
Dim oDocPath
|
||||
Dim oDocPath As String = String.Empty
|
||||
Try
|
||||
oDocPath = GridView1.GetFocusedRowCellValue(GridView1.Columns("FULL_FILE_PATH"))
|
||||
|
||||
|
||||
oDocPath = Convert.ToString(GridView1.GetFocusedRowCellValue(GridView1.Columns("FULL_FILE_PATH")))
|
||||
Catch ex As Exception
|
||||
LOGGER.Warn($"Error getting DocPath in Monitor: {ex.Message}")
|
||||
Exit Sub
|
||||
oDocPath = String.Empty
|
||||
End Try
|
||||
|
||||
' Validierungen einbauen, damit LoadFile_FromPath keine unhandled NullReferenceException wirft
|
||||
If String.IsNullOrWhiteSpace(oDocPath) Then
|
||||
LOGGER.Warn("BarButtonItem3: No document path available")
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
|
||||
If USER_LANGUAGE = "de-DE" Then
|
||||
BarStaticItemInfo.Caption = "Kein Dateipfad verfügbar"
|
||||
Else
|
||||
BarStaticItemInfo.Caption = "No file path available"
|
||||
End If
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
If Not File.Exists(oDocPath) Then
|
||||
LOGGER.Warn($"BarButtonItem3: File does not exist: {oDocPath}")
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
|
||||
If USER_LANGUAGE = "de-DE" Then
|
||||
BarStaticItemInfo.Caption = "Datei nicht vorhanden oder nicht zugreifbar"
|
||||
Else
|
||||
BarStaticItemInfo.Caption = "File is not existing or accessible!"
|
||||
End If
|
||||
If DocumentViewerMonitor IsNot Nothing Then
|
||||
DocumentViewerMonitor.Visible = False
|
||||
End If
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
If DocumentViewerMonitor Is Nothing Then
|
||||
LOGGER.Error("BarButtonItem3: DocumentViewerMonitor is Nothing")
|
||||
MsgBox("Document viewer is not initialized.", MsgBoxStyle.Critical, "DocView")
|
||||
Exit Sub
|
||||
End If
|
||||
|
||||
Try
|
||||
DocumentViewerMonitor.LoadFile_FromPath(oDocPath)
|
||||
Catch ex As Exception
|
||||
LOGGER.Error(ex)
|
||||
BarStaticItemInfo.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
|
||||
BarStaticItemInfo.Caption = "Error loading document"
|
||||
DocumentViewerMonitor.Visible = False
|
||||
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error loading document")
|
||||
End Try
|
||||
DocumentViewerMonitor?.LoadFile_FromPath(oDocPath)
|
||||
|
||||
'If oDocPath <> "" Then
|
||||
' If Not Application.OpenForms().OfType(Of frmValidator).Any Then
|
||||
|
||||
@@ -479,6 +479,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ApplicationEvents.vb" />
|
||||
<Compile Include="ClassCockpit.vb" />
|
||||
<Compile Include="ClassConfig.vb" />
|
||||
<Compile Include="ClassConstants.vb" />
|
||||
<Compile Include="ClassControlCreator.vb" />
|
||||
@@ -920,6 +921,9 @@
|
||||
<DependentUpon>frmLoginAdmin.vb</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="frmMain.aa.resx">
|
||||
<DependentUpon>frmMain.vb</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="frmMain.en.resx">
|
||||
<DependentUpon>frmMain.vb</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
|
||||
Reference in New Issue
Block a user