Jeder Datenbank-Anbieter stellt sein eigenes Instrumentarium bereit, mit dem auf die DB zugegriffen werden kann.
Das Instrumentarium ist gewissermaßen "normiert", durch gemeinsame Basisklassen und Schnittstellen. Daher kann - obwohl alle DB-Systeme unterschiedlich ticken, mit einer gewissen Einheitlichkeit vorgegangen werden.
Dieser DatabaseViewer nutzt zwei Sachen, um Datenbanken möglichst vieler Datenbanksysteme zu explorieren:
Oracle und weitere Anbieter sind nicht getestet, aber wenns mit rechten Dingen zu geht, darfs bei professionellen Anbietern eiglich kein Problem geben.
Für SqLite funktionierts leider nur mit Framework3.5, denn SqLite stellt, soweit ich weiß, noch keine Unterstützung für FW4 bereit (Stand 3-2012).
Für SqLite muß man die dem Framework entsprechende Version der Dll eingebunden haben
SqlServerCe wird erstaunlicherweise nicht unterstützt: NotSupportedException erfolgt beim Abruf des Grund-Schemas, was ich für ein haus-eigenes Produkt von MS ziemlich schwach finde
Unter den verfügbaren Schemata (Datentypen, User-Rechte, Indexe, Constraints, Procedures,...) ist natürlich das Tabellen-Schema von herausragender Bedeutung.
Deshalb entnimmt DataViewer gleich beim Aufruf dem Tabellen-Schema die verfügbaren Tabellen-Namen, und präsentiert sie in einer weiteren Listbox (die erste Listbox präsentiert die verfügbaren Schemata).
Aus diesen Tabellen-Namen kann man ja leicht eine Sql-Query bauen, die dann die Tabellen-Daten abruft (das müsster mir jetzt ohne Bildchen abkaufen ;)).
Die Darstellung im untypisierten DatagridView ist natürlich grauenhaft, aber es ist ja nur ein Tool, um einen Überblick zu gewinnen, wie eine unbekannte DB aufgebaut ist, und ob ühaupt Daten da sind.
Code
frmDataViewer hat eine Sub New, die eine ConnectionFactory erwartet, und beliebig viele String-Segmente, die zum ConnectionString zusammengesetzt werden. In Sub New werden zwei List(Of String) befüllt: die eine mit dem Grund-Schema (Connection.GetSchema()), und die andere mit den Tabellen-Namen (Connection.GetSchema("Tables")) (Zeilen #14 - #17).
Zum Schluß werden 2 Listboxen an die Listen gebunden, und deren SelectedIndexChanged-Event wird abonniert (#19 - #22).
Im SelectedIndexChanged-Handler wird nun je nach auslösender Listbox entweder eine DataTable mit einem Schema erstellt oder ein DataAdapter kriegt ein SelectCommand, mit dem eine bestimmte DB-Tabelle abgerufen wird.
Issn bischen aufwändig gemacht, weil ich bischen Fehler-Catching mache, und auch ins Debug-Fenster logge - ich hoffe, ihr blickt trotzdem durch:
Das war auch schon das ganze Form, und der eigentliche Code des Viewers. Kann man aufrufen wie jedes Form, und wenn man die Sub New nimmt, welche DbProviderFactory und Connectionstring entgegennimmt, kann man halt inne DB browsen - sowohl in den Schemata als auch in den Daten.
Inne Sample-App rufe ich das Form aus einer Sub Main auf, also das VB-AnwendungsFramework ist in diesem Sample in den Projekt-Einstellungen deaktiviert - steht natürlich frei, es auch anders zu halten.
In Sub Main jedenfalls findet sich folgender komischer Code:
Also eine total bescheuerte ElseIf - Kette, von der nur der erste Zweig zur Ausführung kommt.
Das ist Absicht, und praktisch zum Experimentieren: Man kann einfach zB die Zeilen #10-#13 an die Position #7 verschieben, und statt in der SqLite-DB wird dann eben in einem Excel-Workbook gebrowst.
Grad beim Zugriff auf Excel mittels OleDB ist das Tool recht nützlich, weil da kann man sehen, wie die Daten vom DBProvider aufgefasst werden - ein Excel-Worksheet ist ja meist nicht wirklich kompatibel.
Auch die Abfrage von Csv ist interessant - in zweifacher Hinsicht:
(Die Downloads sind übrigens so fett, v.a., weil ich Sample-DBs mit drinne hab - Code ist ja nicht so viel ;).)
Das Instrumentarium ist gewissermaßen "normiert", durch gemeinsame Basisklassen und Schnittstellen. Daher kann - obwohl alle DB-Systeme unterschiedlich ticken, mit einer gewissen Einheitlichkeit vorgegangen werden.
Dieser DatabaseViewer nutzt zwei Sachen, um Datenbanken möglichst vieler Datenbanksysteme zu explorieren:
- die Tatsache, dass jeder DB-Anbieter auch eine DBProviderFactory bereitstellt, mit der man sich das weitere Instrumentarium für den DB-Zugriff generieren lassen kann.
- die Connection.GetSchema() - Methode
Connection.GetSchema() gibts in zwei Überladungen, die jeweils eine DataTable zurückgeben:
- Connection.GetSchema() ohne Parameter ruft das Grund-Schema ab, welches überhaupt angibt, welche Schemata abgerufen werden können. Das mag so aussehen:
Erkennbar, dasses sich um einen DBProvider handelt, der eine Rechte-Verteilung unterstützt (Schema "users"), und auch stored Procedures, inklusive Parametern (MySql).
- Dem Grundschema kann man die Namen der verfügbaren Schemata entnehmen, und kann diese dann mit der parametrisierten Überladung von .Getschema(schemaName) weiter abfragen - der Abruf von Connection.GetSchema("DataTypes") liefert für MySql zB folgende Information:
(Ich habe die Spaltenbreiten so schmal wie möglich gemacht, weil es gibt u.U. sehr viele Spalten - und mit den Tooltips kommt man zur Not ja auch hin)
- Connection.GetSchema() ohne Parameter ruft das Grund-Schema ab, welches überhaupt angibt, welche Schemata abgerufen werden können. Das mag so aussehen:
Oracle und weitere Anbieter sind nicht getestet, aber wenns mit rechten Dingen zu geht, darfs bei professionellen Anbietern eiglich kein Problem geben.
Für SqLite muß man die dem Framework entsprechende Version der Dll eingebunden haben
SqlServerCe wird erstaunlicherweise nicht unterstützt: NotSupportedException erfolgt beim Abruf des Grund-Schemas, was ich für ein haus-eigenes Produkt von MS ziemlich schwach finde
Unter den verfügbaren Schemata (Datentypen, User-Rechte, Indexe, Constraints, Procedures,...) ist natürlich das Tabellen-Schema von herausragender Bedeutung.
Deshalb entnimmt DataViewer gleich beim Aufruf dem Tabellen-Schema die verfügbaren Tabellen-Namen, und präsentiert sie in einer weiteren Listbox (die erste Listbox präsentiert die verfügbaren Schemata).
Aus diesen Tabellen-Namen kann man ja leicht eine Sql-Query bauen, die dann die Tabellen-Daten abruft (das müsster mir jetzt ohne Bildchen abkaufen ;)).
Die Darstellung im untypisierten DatagridView ist natürlich grauenhaft, aber es ist ja nur ein Tool, um einen Überblick zu gewinnen, wie eine unbekannte DB aufgebaut ist, und ob ühaupt Daten da sind.
Code
frmDataViewer hat eine Sub New, die eine ConnectionFactory erwartet, und beliebig viele String-Segmente, die zum ConnectionString zusammengesetzt werden. In Sub New werden zwei List(Of String) befüllt: die eine mit dem Grund-Schema (Connection.GetSchema()), und die andere mit den Tabellen-Namen (Connection.GetSchema("Tables")) (Zeilen #14 - #17).
VB.NET-Quellcode
- Public Class frmDataViewer2008
- Private _SchemaNames As New List(Of String)
- Private _TableNames As New List(Of String)
- Private _Con As DbConnection
- Private _Factory As DbProviderFactory
- Public Sub New(ByVal fct As DbProviderFactory, ByVal ParamArray sCon() As String)
- MyClass.New()
- _Factory = fct
- _Con = fct.CreateConnection
- _con.ConnectionString = String.Concat(sCon)
- _con.Open()
- Using generalSchema = _con.GetSchema(), tableSchema = _con.GetSchema("Tables")
- _SchemaNames.AddRange(From rw In generalSchema Select Name = rw(0).ToString)
- _TableNames.AddRange(From rw In tableSchema Select Name = rw("TABLE_NAME").ToString)
- End Using
- _Con.Close()
- lstSchema.DataSource = _SchemaNames
- lstTable.DataSource = _TableNames
- AddHandler lstSchema.SelectedIndexChanged, AddressOf DbTable_SelectedIndexChanged
- AddHandler lstTable.SelectedIndexChanged, AddressOf DbTable_SelectedIndexChanged
- DbTable_SelectedIndexChanged(lstSchema, EventArgs.Empty)
- End Sub
Im SelectedIndexChanged-Handler wird nun je nach auslösender Listbox entweder eine DataTable mit einem Schema erstellt oder ein DataAdapter kriegt ein SelectCommand, mit dem eine bestimmte DB-Tabelle abgerufen wird.
Issn bischen aufwändig gemacht, weil ich bischen Fehler-Catching mache, und auch ins Debug-Fenster logge - ich hoffe, ihr blickt trotzdem durch:
VB.NET-Quellcode
- Private Sub DbTable_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
- If lstTable.SelectedIndex < 0 Then Return
- Dim tb = TryCast(Grid.DataSource, DataTable)
- If tb IsNot Nothing Then tb.Dispose()
- Grid.DataSource = Nothing
- _Con.Open()
- Select Case True
- Case sender Is lstSchema
- Dim schema = _SchemaNames(lstSchema.SelectedIndex)
- Dim msg = "Connection.GetSchema(""" & schema & """)"
- Debug.Write(msg & " ")
- Try
- Grid.DataSource = _Con.GetSchema(schema)
- Debug.WriteLine("")
- Catch ex As Exception
- Debug.WriteLine("Failed: " & ex.Message)
- MessageBox.Show(msg & " konnte nicht ausgeführt wern")
- End Try
- Case sender Is lstTable
- tb = New DataTable
- Dim sTable = _TableNames(lstTable.SelectedIndex)
- Using adp = _Factory.CreateDataAdapter, cmd = _Factory.CreateCommand
- adp.SelectCommand = cmd
- cmd.Connection = _Con
- cmd.CommandText = "Select * from `" & sTable & "`"
- Debug.Write(cmd.CommandText & " ")
- Try
- adp.Fill(tb)
- Debug.WriteLine("")
- Catch ex As Exception
- cmd.CommandText = "Select * from [" & sTable & "]"
- Debug.Write(cmd.CommandText & " ")
- Try
- adp.Fill(tb)
- Debug.WriteLine("")
- Catch ex2 As Exception
- Debug.WriteLine("Failed: " & ex2.Message)
- MessageBox.Show("""" & cmd.CommandText & """: Abfrage konnte nicht ausgeführt wern")
- End Try
- End Try
- Grid.DataSource = tb
- End Using
- End Select
- _Con.Close()
- End Sub
Das war auch schon das ganze Form, und der eigentliche Code des Viewers. Kann man aufrufen wie jedes Form, und wenn man die Sub New nimmt, welche DbProviderFactory und Connectionstring entgegennimmt, kann man halt inne DB browsen - sowohl in den Schemata als auch in den Daten.
Inne Sample-App rufe ich das Form aus einer Sub Main auf, also das VB-AnwendungsFramework ist in diesem Sample in den Projekt-Einstellungen deaktiviert - steht natürlich frei, es auch anders zu halten.
In Sub Main jedenfalls findet sich folgender komischer Code:
VB.NET-Quellcode
- <STAThread()> _
- Public Sub Main(ByVal commandLineArgs As String())
- Application.EnableVisualStyles()
- Application.SetCompatibleTextRenderingDefault(False)
- Dim frm As frmDataViewer2008 = Nothing, dataPath = ""
- If True Then
- dataPath = Path.GetFullPath("..\..\Data\OrderDB.s3db")
- frm = New frmDataViewer2008(SQLite.SQLiteFactory.Instance, "Data Source=", dataPath)
- ElseIf True Then
- dataPath = Path.GetFullPath("..\..\Data\Kartenliste WoW TCG Starter.xls")
- frm = New frmDataViewer2008(OleDbFactory.Instance, _
- "Provider=Microsoft.Jet.OLEDB.4.0; Extended Properties=""Excel 8.0""; Data Source='", dataPath, "';")
- ElseIf True Then
- dataPath = Path.GetFullPath("..\..\Data\Fotos.mdb")
- frm = New frmDataViewer2008(OleDbFactory.Instance, _
- "Provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=True; Data Source='", dataPath, "';")
- ElseIf True Then
- dataPath = Path.GetFullPath("..\..\Data\Csv")
- frm = New frmDataViewer2008(OleDbFactory.Instance, _
- "Provider=Microsoft.Jet.OLEDB.4.0; Extended Properties=""text;HDR=Yes;FMT=Delimited""; Data Source='", dataPath, "';")
- ElseIf True Then
- 'SqlCe unterstützt keinen Abruf von Schema-Informationen
- dataPath = Path.GetFullPath("..\..\Data\Bestellungen.sdf")
- frm = New frmDataViewer2008(SqlCeProviderFactory.Instance, "Data Source='", dataPath, "';")
- ElseIf True Then
- 'MySql auf db4Free: Passwort disabled
- frm = New frmDataViewer2008(MySqlClientFactory.Instance, _
- "server=w00cb7ca.kasserver.com;user id=XXXXXX;password=XXXXXXX;persist security info=True;database=XXXXXX")
- ElseIf True Then
- End If
- Application.Run(frm)
- My.Settings.Save()
- End Sub
Das ist Absicht, und praktisch zum Experimentieren: Man kann einfach zB die Zeilen #10-#13 an die Position #7 verschieben, und statt in der SqLite-DB wird dann eben in einem Excel-Workbook gebrowst.
Grad beim Zugriff auf Excel mittels OleDB ist das Tool recht nützlich, weil da kann man sehen, wie die Daten vom DBProvider aufgefasst werden - ein Excel-Worksheet ist ja meist nicht wirklich kompatibel.
Auch die Abfrage von Csv ist interessant - in zweifacher Hinsicht:
- Zunächst mal ist zu beachten, dass beim Csv-Abruf nicht eine Datei im ConnectionString anzugeben ist, sondern
Alle Csv-Dateien eines Directories werden gemeinsam als Datenbank aufgefasst.
- Weiters ist wesentlich, was in der Registry als Csv-Delimiter (Spaltentrenner) angegeben ist. Bei mir zB. ist "," der Delimiter, und deshalb ist meine Csv-Ansicht Schrott, weil die Daten wurden aus Excel exportiert, und das verwendete ";" als Delimiter.
(Die Downloads sind übrigens so fett, v.a., weil ich Sample-DBs mit drinne hab - Code ist ja nicht so viel ;).)
Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „ErfinderDesRades“ ()