Imports guinet Imports Newtonsoft.Json ''' ''' Schnittstelle zwischen GUIXT und MS SQL-Server ''' Public Class iface Private guixt As New guinet.guixt ''' ''' Datenbankverbindung wird geprüft. ''' ''' Verbindungszeichenfolge ''' Gibt eine leere Zeichenfolge ("") oder die Fehlermeldung zurück. Public Function CheckConnection(ConnectionString As String) As String Try 'Beispiel für eine Verbindungszeichenfolge mit SQL Server-Authentifizierung: 'Data Source=MySQLServer;Initial Catalog=MyDatabase;Persist Security Info=True;User ID=MyUsername;Password=MyPassword 'Beispiel für eine Verbindungszeichenfolge mit Windows-Authentifizierung: 'Data Source=MySQLServer;Initial Catalog=MyDatabase;Integrated Security=True; 'Initialisiert eine neue Instanz der SqlConnection-Klasse mit der Verbindungszeichenfolge. Dim cnn As New SqlClient.SqlConnection(ConnectionString) 'Öffnet die Datenbankverbindung. cnn.Open() 'Schließt die Verbindung mit der Datenbank. cnn.Close() 'leere Zeichenfolge ("") Return String.Empty Catch ex As Exception 'Fehlermeldung Return ex.Message End Try End Function ''' ''' Ermittelt die Datensätze der SELECT-SQL-Anweisung und schreibt das Ergebnis auf die angegebene GuiXT-Langtextvariablen (data) im JSON-Format zurück. ''' ''' Verbindungszeichenfolge ''' Text der SELECT-SQL-Anweisung. ''' Name der GuiXT-Langtextvariablen ''' Gibt eine leere Zeichenfolge ("") oder die Fehlermeldung zurück. Public Function SelectRow(ConnectionString As String, cmdText As String, data As String) As String Try ' Beispiele für SELECT-SQL-Anweisungen: ' SELECT [DISTINCT] FROM [WHERE ...] [GROUP BY ...] ' cmdText = "SELECT * FROM Customers" ' cmdText = "SELECT * FROM Customers WHERE CustomerID = 'TEST'" ' cmdText = "SELECT * FROM Customers WHERE Country = 'Germany' AND City = 'Berlin'" ' cmdText = "SELECT DISTINCT Country FROM Customers ORDER BY Country" ' cmdText = "SELECT DISTINCT City FROM Customers ORDER BY City" ' cmdText = "SELECT DISTINCT City FROM Customers WHERE Country = '?' ORDER BY City" ' cmdText = "SELECT * FROM Customers WHERE Country = '?'" ' cmdText = "SELECT * FROM Customers WHERE Country = '?' AND City = '?'" 'Initialisiert eine neue Instanz der SqlConnection-Klasse mit der Verbindungszeichenfolge. Dim cnn As New SqlClient.SqlConnection(ConnectionString) 'Öffnet die Datenbankverbindung. cnn.Open() 'Initialisiert eine neue Instanz einer Transact-SQL-Anweisung. Dim cmd As New SqlClient.SqlCommand(cmdText, cnn) 'Initialisiert eine neue Instanz einer Tabelle. Dim dt As New DataTable 'Füllt die Tabelle mit Werten und Informationen über Spalten und Primärschlüssel aus der Datenquelle. dt.Load(cmd.ExecuteReader(CommandBehavior.KeyInfo)) 'Schließt die Verbindung mit der Datenbank. cnn.Close() 'Konvertiert die Daten der Tabelle in das JSON-Format. Dim JsonString As String = JsonConvert.SerializeObject(dt) 'Legt den Wert einer GuiXT-Langtextvariablen fest. Dim RetVal As Boolean = guixt.SetText(data, JsonString) 'leere Zeichenfolge ("") Return String.Empty Catch ex As Exception 'Fehlermeldung Return ex.Message End Try End Function ''' ''' Aktualisiert die im JSON-Format übergebenen Datensätze in der Datenbank. ''' ''' Verbindungszeichenfolge ''' Name der Ziel-Tabelle ''' Datensatzzeile(n) im JSON-Format ''' Name der GuiXT-Langtextvariablen für die Datensatzzeile(n) im JSON-Format ''' Gibt eine leere Zeichenfolge ("") oder die Fehlermeldung zurück. Public Function UpdateRow(ConnectionString As String, tableName As String, row As String, Optional rowtextname As String = "") As String Try 'Hole den Wert einer GuiXT-Langtextvariablen. If rowtextname.Trim.Length > 0 Then row = guixt.GetText(rowtextname) End If 'JSON-Zeichenfolge wird für die Konvertierung aufbereitet: '- Sonderzeichen ChrW(31) (Silbentrennung) wird entfernt '- Eckige Klammern (Tabellenkennzeichen) wird hinzugefügt row = "[" & row.Replace(ChrW(31), "'") & "]" 'Konvertierung des JSON-Formats in eine Tabelle. Dim dt As DataTable = JsonConvert.DeserializeObject(Of DataTable)(row) 'Initialisiert eine neue Instanz der SqlConnection-Klasse mit der Verbindungszeichenfolge. Dim cnn As New SqlClient.SqlConnection(ConnectionString) 'Öffnet die Datenbankverbindung. cnn.Open() 'Leere Tabelle mit Spalten- und Primärschlüssel-Informationen. Dim dtSchema As DataTable = GetDtSchema(cnn, tableName) 'Liste der Spaltennamen ohne Primärschüssel Dim lCols As List(Of String) = GetColumnsWithoutPk(dtSchema) 'Liste der Primärschüsselnamen Dim lPks As List(Of String) = GetColumnsPk(dtSchema) 'Liste der Spaltenname mit Parameternamen ohne Primärschlüssel Dim lColsUpdate As List(Of String) = GetColumnsWithoutPkUpdate(dtSchema) 'Liste der Primärschlüsselnamen mit Parameternamen Dim lPksWhere As List(Of String) = GetColumnsPkWhere(dtSchema) 'Sicherheitsabfrage, existiert kein Primärschlüssel wird die Funktion abgebrochen. If lPks.Count = 0 Then cnn.Close() Throw New Exception("No PrimaryKey!") End If 'UPDATE-SQL-Anweisung 'z.B.: UPDATE Customers SET CompanyName = @CompanyName, ContactName = @ContactName, ContactTitle = @ContactTitle, Address = @Address, City = @City, Region = @Region, PostalCode = @PostalCode, Country = @Country, Phone = @Phone, Fax = @Fax WHERE CustomerID = @CustomerID Dim sb As New System.Text.StringBuilder sb.Append("UPDATE " & tableName & " SET ") sb.Append(String.Join(", ", lColsUpdate.ToArray)) sb.Append(" WHERE ") sb.Append(String.Join(" AND ", lPksWhere.ToArray)) Dim cmdText As String = sb.ToString 'Initialisiert eine neue Instanz einer UPDATE-SQL-Anweisung mit Text und Parametern. Dim cmd As New SqlClient.SqlCommand(cmdText, cnn) cmd.CommandText = cmdText For Each columnName As String In lCols cmd.Parameters.Add(GetParameter(dtSchema, columnName)) Next For Each columnName As String In lPks cmd.Parameters.Add(GetParameter(dtSchema, columnName)) Next Dim i As Integer = 0 Dim r As Integer = 0 Dim s As String = String.Empty Dim sbError As New System.Text.StringBuilder 'Zeilen der Tabelle werden durchlaufen. For Each dr As DataRow In dt.Rows i += 1 s = String.Empty 'Die Werte der Parameter der UPDATE-SQL-Anweisung werden belegt. For Each dc As DataColumn In dtSchema.Columns If dr(dc.ColumnName).ToString.Trim.Length = 0 Then cmd.Parameters("@" & dc.ColumnName).Value = DBNull.Value Else cmd.Parameters("@" & dc.ColumnName).Value = dr(dc.ColumnName) End If If dt.PrimaryKey.Contains(dc) Then If s.Length = 0 Then s = String.Format("{0} = {1}", dc.ColumnName, dr(dc.ColumnName).ToString) Else s = " AND " & String.Format("{0} = {1}", dc.ColumnName, dr(dc.ColumnName).ToString) End If End If Next Try 'Führt die Update-SQL-Anweisung aus und gibt die Anzahl der betroffenen Zeilen zurück. r = cmd.ExecuteNonQuery() Catch ex1 As Exception 'Fehlermeldung s = s & " ERROR: " & ex1.Message.Replace(vbNewLine, " ") sbError.AppendLine(String.Format("{0,3}|{1,6}|{2}", i, r, s)) End Try Next 'Schließt die Verbindung mit der Datenbank. cnn.Close() 'Fehlermeldung, falls vorhanden. Return sbError.ToString Catch ex As Exception 'Fehlermeldung Return ex.Message End Try End Function ''' ''' Fügt die im JSON-Format übergebenen Datensätze in die Datenbank ein. ''' ''' Verbindungszeichenfolge ''' Name der Ziel-Tabelle ''' Datensatzzeile(n) im JSON-Format ''' Name der GuiXT-Langtextvariablen für die Datensatzzeile(n) im JSON-Format ''' Gibt eine leere Zeichenfolge ("") oder die Fehlermeldung zurück. Public Function InsertRow(ConnectionString As String, tableName As String, row As String, Optional rowtextname As String = "") As String Try 'Hole den Wert einer GuiXT-Langtextvariablen. If rowtextname.Trim.Length > 0 Then row = guixt.GetText(rowtextname) End If 'JSON-Zeichenfolge wird für die Konvertierung aufbereitet: '- Sonderzeichen ChrW(31) (Silbentrennung) wird entfernt '- Eckige Klammern (Tabellenkennzeichen) wird hinzugefügt row = "[" & row.Replace(ChrW(31), "'") & "]" 'Konvertierung des JSON-Formats in eine Tabelle. Dim dt As DataTable = JsonConvert.DeserializeObject(Of DataTable)(row) 'Initialisiert eine neue Instanz der SqlConnection-Klasse mit der Verbindungszeichenfolge. Dim cnn As New SqlClient.SqlConnection(ConnectionString) 'Öffnet die Datenbankverbindung. cnn.Open() 'Leere Tabelle mit Spalten- und Primärschlüssel-Informationen. Dim dtSchema As DataTable = GetDtSchema(cnn, tableName) 'Liste der Spaltennamen Dim lCols As List(Of String) = GetColumns(dtSchema) 'INSERT-SQL-Anweisung 'z.B.: INSERT INTO Customers (CustomerID, CompanyName, ContactName, ContactTitle, Address, City, Region, PostalCode, Country, Phone, Fax) VALUES (@CustomerID, @CompanyName, @ContactName, @ContactTitle, @Address, @City, @Region, @PostalCode, @Country, @Phone, @Fax) Dim sb As New System.Text.StringBuilder sb.Append("INSERT INTO " & tableName & " (") sb.Append(String.Join(", ", lCols.ToArray)) sb.Append(") VALUES (") sb.Append("@" & String.Join(", @", lCols.ToArray)) sb.Append(")") Dim cmdText As String = sb.ToString 'Initialisiert eine neue Instanz einer INSERT-SQL-Anweisung mit Text und Parametern. Dim cmd As New SqlClient.SqlCommand(cmdText, cnn) cmd.CommandText = cmdText For Each columnName As String In lCols cmd.Parameters.Add(GetParameter(dtSchema, columnName)) Next Dim i As Integer = 0 Dim r As Integer = 0 Dim s As String = String.Empty Dim sbError As New System.Text.StringBuilder 'Zeilen der Tabelle werden durchlaufen. For Each dr As DataRow In dt.Rows i += 1 s = String.Empty 'Die Werte der Parameter der INSERT-SQL-Anweisung werden belegt. For Each dc As DataColumn In dtSchema.Columns If dr(dc.ColumnName).ToString.Trim.Length = 0 Then cmd.Parameters("@" & dc.ColumnName).Value = DBNull.Value Else cmd.Parameters("@" & dc.ColumnName).Value = dr(dc.ColumnName) End If If dt.PrimaryKey.Contains(dc) Then If s.Length = 0 Then s = String.Format("{0} = {1}", dc.ColumnName, dr(dc.ColumnName).ToString) Else s = " AND " & String.Format("{0} = {1}", dc.ColumnName, dr(dc.ColumnName).ToString) End If End If Next Try 'Führt die INSERT-SQL-Anweisung aus und gibt die Anzahl der betroffenen Zeilen zurück. r = cmd.ExecuteNonQuery() Catch ex1 As Exception 'Fehlermeldung s = s & " ERROR: " & ex1.Message.Replace(vbNewLine, " ") sbError.AppendLine(String.Format("{0,3}|{1,6}|{2}", i, r, s)) End Try Next 'Schließt die Verbindung mit der Datenbank. cnn.Close() 'Fehlermeldung, falls vorhanden. Return sbError.ToString Catch ex As Exception 'Fehlermeldung Return ex.Message End Try End Function ''' ''' Löscht die im JSON-Format übergebenen Datensätze aus der Datenbank. ''' ''' Verbindungszeichenfolge ''' Name der Ziel-Tabelle ''' Datensatzzeile(n) im JSON-Format ''' Name der GuiXT-Langtextvariablen für die Datensatzzeile(n) im JSON-Format ''' Gibt eine leere Zeichenfolge ("") oder die Fehlermeldung zurück. Public Function DeleteRow(ConnectionString As String, tableName As String, row As String, Optional rowtextname As String = "") As String Try 'Hole den Wert einer GuiXT-Langtextvariablen. If rowtextname.Trim.Length > 0 Then row = guixt.GetText(rowtextname) End If 'JSON-Zeichenfolge wird für die Konvertierung aufbereitet: '- Sonderzeichen ChrW(31) (Silbentrennung) wird entfernt '- Eckige Klammern (Tabellenkennzeichen) wird hinzugefügt row = "[" & row.Replace(ChrW(31), "'") & "]" 'Konvertierung des JSON-Formats in eine Tabelle. Dim dt As DataTable = JsonConvert.DeserializeObject(Of DataTable)(row) 'Initialisiert eine neue Instanz der SqlConnection-Klasse mit der Verbindungszeichenfolge. Dim cnn As New SqlClient.SqlConnection(ConnectionString) 'Öffnet die Datenbankverbindung. cnn.Open() 'Leere Tabelle mit Spalten- und Primärschlüssel-Informationen. Dim dtSchema As DataTable = GetDtSchema(cnn, tableName) 'Liste der Primärschüsselnamen Dim lPks As List(Of String) = GetColumnsPk(dtSchema) 'Liste der Primärschlüsselnamen mit Parameternamen Dim lPksWhere As List(Of String) = GetColumnsPkWhere(dtSchema) 'Sicherheitsabfrage, existiert kein Primärschlüssel wird die Funktion abgebrochen. If lPks.Count = 0 Then cnn.Close() Throw New Exception("No PrimaryKey!") End If 'DELETE-SQL-Anweisung 'z.B.: DELETE FROM Customers WHERE CustomerID = @CustomerID Dim sb As New System.Text.StringBuilder sb.Append("DELETE FROM " & tableName & " WHERE ") sb.Append(String.Join(" AND ", lPksWhere.ToArray)) Dim cmdText As String = sb.ToString 'Initialisiert eine neue Instanz einer DELETE-SQL-Anweisung mit Text und Parametern. Dim cmd As New SqlClient.SqlCommand(cmdText, cnn) cmd.CommandText = cmdText For Each columnName As String In lPks cmd.Parameters.Add(GetParameter(dtSchema, columnName)) Next Dim i As Integer = 0 Dim r As Integer = 0 Dim s As String = String.Empty Dim sbError As New System.Text.StringBuilder 'Zeilen der Tabelle werden durchlaufen. For Each dr As DataRow In dt.Rows i += 1 s = String.Empty 'Die Werte der Parameter der DELETE-SQL-Anweisung werden belegt. For Each dc As DataColumn In dtSchema.PrimaryKey If dr(dc.ColumnName).ToString.Trim.Length = 0 Then cmd.Parameters("@" & dc.ColumnName).Value = DBNull.Value Else cmd.Parameters("@" & dc.ColumnName).Value = dr(dc.ColumnName) End If If s.Length = 0 Then s = String.Format("{0} = {1}", dc.ColumnName, dr(dc.ColumnName).ToString) Else s = " AND " & String.Format("{0} = {1}", dc.ColumnName, dr(dc.ColumnName).ToString) End If Next Try 'Führt die DELETE-SQL-Anweisung aus und gibt die Anzahl der betroffenen Zeilen zurück. r = cmd.ExecuteNonQuery() Catch ex1 As Exception 'Fehlermeldung s = s & " ERROR: " & ex1.Message.Replace(vbNewLine, " ") sbError.AppendLine(String.Format("{0,3}|{1,6}|{2}", i, r, s)) End Try Next 'Schließt die Verbindung mit der Datenbank. cnn.Close() 'Fehlermeldung, falls vorhanden Return sbError.ToString Catch ex As Exception 'Fehlermeldung Return ex.Message End Try End Function ''' ''' Gibt eine Leere Tabelle mit Spalten- und Primärschlüssel-Informationen zurück. ''' ''' Instanz der SqlConnection-Klasse ''' Name der Tabelle ''' Leere Tabelle mit Spalten- und Primärschlüssel-Informationen. Private Function GetDtSchema(cnn As SqlClient.SqlConnection, tableName As String) As DataTable 'Transact-SQL-Anweisung Dim cmdText As String = String.Format("SELECT TOP 1 * FROM {0}", tableName) 'Initialisiert eine neue Instanz einer Transact-SQL-Anweisung. Dim cmd As New SqlClient.SqlCommand(cmdText, cnn) 'Initialisiert eine neue Instanz einer Tabelle. Dim dt As New DataTable 'Füllt die Tabelle mit Werten und Informationen über Spalten und Primärschlüssel aus der Datenquelle. dt.Load(cmd.ExecuteReader(CommandBehavior.KeyInfo Or CommandBehavior.SchemaOnly)) 'Gibt die Tabelle zurück. Return dt End Function ''' ''' Gibt eine Liste aller Spaltennamen der Tabelle zurück. ''' ''' Tabelle ''' Liste der Spaltennamen Private Function GetColumns(dt As DataTable) As List(Of String) Dim l As New List(Of String) For Each dc As DataColumn In dt.Columns l.Add(dc.ColumnName) Next Return l End Function ''' ''' Gibt eine Liste der Primärschüsselnamen der Tabelle zurück. ''' ''' Tabelle ''' Liste der Primärschüsselnamen Private Function GetColumnsPk(dt As DataTable) As List(Of String) Dim l As New List(Of String) For Each dc As DataColumn In dt.PrimaryKey l.Add(dc.ColumnName) Next Return l End Function ''' ''' Gibt eine Liste der Spaltennamen ohne Primärschüssel der Tabelle zurück. ''' ''' Tabelle ''' Liste der Spaltennamen ohne Primärschüssel Private Function GetColumnsWithoutPk(dt As DataTable) As List(Of String) Dim l As New List(Of String) For Each dc As DataColumn In dt.Columns If Not dt.PrimaryKey.Contains(dc) Then l.Add(dc.ColumnName) End If Next Return l End Function ''' ''' Gibt eine Liste der Spaltennamen mit Parameternamen ohne Primärschlüssel für die UPDATE-SQL-Anweisung zurück. ''' ''' Tabelle ''' Liste der Spaltenname mit Parameternamen ohne Primärschlüssel Private Function GetColumnsWithoutPkUpdate(dt As DataTable) As List(Of String) Dim l As New List(Of String) For Each dc As DataColumn In dt.Columns If Not dt.PrimaryKey.Contains(dc) Then l.Add(String.Format("{0} = @{0}", dc.ColumnName)) End If Next Return l End Function ''' ''' Gibt eine Liste der Primärschlüsselnamen mit Parameternamen für die WHERE-Klause der SQL-Anweisung zurück. ''' ''' Tabelle ''' Liste der Primärschlüsselnamen mit Parameternamen Private Function GetColumnsPkWhere(dt As DataTable) As List(Of String) Dim l As New List(Of String) For Each dc As DataColumn In dt.PrimaryKey l.Add(String.Format("{0} = @{0}", dc.ColumnName)) Next Return l End Function ''' ''' Gibt eine Instanz eines Parameters zurück, für die Transact-SQL-Anweisung. ''' ''' ''' ''' SqlParameter Private Function GetParameter(dt As DataTable, columnName As String) As SqlClient.SqlParameter Dim parameterName As String = "@" & columnName Dim dbType As SqlDbType = GetDBType(dt.Columns(columnName).DataType) Dim para As New SqlClient.SqlParameter(parameterName, dbType) Return para End Function ''' ''' Gibt den SqlDbType zum DbType zurück. ''' ''' DbType ''' SqlDbType Private Function GetDBType(ByVal theType As System.Type) As SqlDbType Dim p1 As System.Data.SqlClient.SqlParameter Dim tc As System.ComponentModel.TypeConverter p1 = New System.Data.SqlClient.SqlParameter() tc = System.ComponentModel.TypeDescriptor.GetConverter(p1.DbType) If tc.CanConvertFrom(theType) Then p1.DbType = CType(tc.ConvertFrom(theType.Name), DbType) Else Try p1.DbType = CType(tc.ConvertFrom(theType.Name), DbType) Catch __unusedException1__ As Exception End Try End If Return p1.SqlDbType End Function End Class