VB .NET - DataSets und DataTables aus einer XML-Datei in eine SQL Datenbank schreiben
22. Dec 2008 17:01 (bearbeiten)
Ich habe heute nach einer Möglichkeit gesucht, Daten, die ich aus einer SQL Tabelle eines Servers "A" in ein XML-Dataset geschrieben habe, wieder aus diesem XML Dataset zurück in die SQL Tabelle auf dem Server "B" zu schreiben.
Aufgabe war, vier Tabellen von unserem Firmenserver auf die Server draußen bei unseren Mitarbeiter per Programm zu übertragen.
Mein Hauptproblem bei solchen Aufgaben ist eigentlich immer das Erstellen der SQL-Befehle fürs Updaten oder Inserten. Wobei, Problem ist eventuell zu viel gesagt, viel eher nervt es, manuell diese Statements zusammenbauen zu müssen.
Da .NET ja intern über die TableAdapter und DataProvider die Funktion besitzt, eben diese SQL Befehle automatisch zu generieren, dachte ich mir, warum nicht diese Fähigkeit nutzen und mir damit das Getippe und das Prüfen der selbst erstellten SQL Statements zu ersparen.
Die Hauptarbeit in der wichtigsten Funktion ImportTableToSQL übernimmt dabei die Klasse SQLCommandBuilder, die einen DataAdapter mit dem einzutragenden DataSet übergeben bekommt. Anschließend weisen wir dem SQLCommandBuilder für alle Parameter einfach die Werte zu, die in unserem DataSet bereits drin stehen.
Zu guter letzt führen wir den automatisch generierten Insert-Befehl des SQLCommandBuilders aus, et voila, die Tabellen sind aktuell.
Hier der Code, um Daten aus dem SQL-Server in ein XML Dataset zu schreiben. Die wichtigste Stelle hierbei ist Dataset.WriteXML().
''' <summary> ''' Exports a Table from a SQL Database to a XML file ''' </summary> ''' <param name="aSelectStatement">Select Statement for the data which should be exported</param> ''' <param name="aTableName">Name of the Table (needed for creating the filename)</param> ''' <param name="aOutputXMLDirectory">Ausgabe-Verzeichnis</param> ''' <param name="aOutputXMLFilename">Ausgabe-Dateiname ohne Dateiendung und ohne Pfadangabe</param> ''' <param name="aDatasetName"></param> ''' <param name="Append">An bestehende XML-Datei anhängen (INFER-Modus)</param> ''' <remarks></remarks> Public Shared Sub ExportTable(ByVal strCon As String, _ ByVal aSelectStatement As String, _ ByVal aTableName As String, _ ByVal aOutputXMLDirectory As String, _ Optional ByVal aOutputXMLFilename As String = "", _ Optional ByVal aDatasetName As String = "NewDataSet", _ Optional ByVal CreateSchemaFiles As Boolean = False, _ Optional ByVal Append As Boolean = False) Using con As SqlClient.SqlConnection = New SqlClient.SqlConnection(strCon) Try con.Open() Dim ds As New DataSet(aDatasetName) Dim da As SqlClient.SqlDataAdapter = New SqlClient.SqlDataAdapter(aSelectStatement, con) da.FillSchema(ds, SchemaType.Source, aTableName) da.Fill(ds, aTableName) ' Create Filename Dim strFullFilename As String ' Trailing backslash? If Not aOutputXMLDirectory.EndsWith("\") Then aOutputXMLDirectory += "\" ' Create dir If Not System.IO.Directory.Exists(aOutputXMLDirectory) Then System.IO.Directory.CreateDirectory(aOutputXMLDirectory) End If ' Filename given? If aOutputXMLFilename = "" Then If aTableName = "" Then aTableName = My.Computer.FileSystem.GetTempFileName End If aOutputXMLFilename = aTableName End If ' Create filename strFullFilename = aOutputXMLDirectory & aOutputXMLFilename ' If XML-File already exists use it and add information to it If Append Then ds.ReadXml(strFullFilename & ".XML", XmlReadMode.InferSchema) End If End If ' Write XML ds.WriteXml(strFullFilename & ".XML") ' Write Schema? If CreateSchemaFiles Then ds.WriteXmlSchema(strFullFilename & ".XSD") ' Done Catch ex As Exception End Try End Using End Sub
Die folgende Funktion durchsucht ein Verzeichnis nach XML- und XSD-Dateien. Aus den gefundenen Dateien wird ein Dataset erstellt und dies weiter an die Prozedur ImportDatasetToSQL gegeben.
''' <summary> ''' Importiert Daten aus XML Dateien in eine SQL Server Tabelle ''' </summary> ''' <param name="aXMLSourceDirectory">Quellverzeichnis der XML-Dateien, die importiert werden sollen</param> ''' <param name="aSQLConnectionString">SQL Verbindungsstring</param> ''' <remarks></remarks> Public Shared Sub ImportTablesToSQL(ByVal aXMLSourceDirectory As String, ByVal aSQLConnectionString As String) Dim filters As String() = {"*.XML"} Dim lstFiles As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = _ My.Computer.FileSystem.GetFiles(aXMLSourceDirectory, FileIO.SearchOption.SearchAllSubDirectories, filters) For Each fn As String In lstFiles Dim ds As New DataSet Try ' Read the schema ' Filename is the same as the xml file except its extension ds.ReadXmlSchema(fn.Replace(".XML", ".XSD")) ' Read the XML File ds.ReadXml(fn) 'For Each tbl As DataTable In ds.Tables ' Debug.Print("Table: " & tbl.TableName) ' For Each cc As System.Data.Constraint In tbl.Constraints ' Debug.Print("Constraint: " & cc.ConstraintName) ' Next ' For Each pkcol As DataColumn In tbl.PrimaryKey ' Debug.Print("Primary Key: " & pkcol.ColumnName) ' Next 'Next ImportDatasetToSQL(ds, aSQLConnectionString) Catch ex As Exception Continue For End Try Next End Sub
Diese Funktion importiert jede Tabelle des Datasets in die SQL-Tabelle mit dem selben Namen.
Private Shared Sub ImportDatasetToSQL(ByRef aDataset As DataSet, ByVal aSQLConnectionString As String) Using con As New SqlClient.SqlConnection(aSQLConnectionString) Try con.Open() Catch ex As Exception Exit Sub End Try Try For Each tbl As DataTable In aDataset.Tables ImportTableToSQL(tbl, con) Next Catch ex As Exception End Try con.Close() End Using End Sub
Hier nun die eigentliche Import-Funktion.
Wir übergeben hier ein DataTable und einen SQL Connectionstring. Im DataTable sind die Werte drin, die in die SQL Datenbank geschrieben werden sollen.
Private Shared Sub ImportTableToSQL(ByRef aDataTable As DataTable, ByRef aConnection As SqlClient.SqlConnection) ' Create a command for the DataAdapter Dim cmd As New SqlClient.SqlCommand("Select * From " & aDataTable.TableName, aConnection) ' Create the DataAdapter (needed for creating the sql-statement) Dim da As New SqlClient.SqlDataAdapter(cmd) ' Fill our DataAdapter with Data from our DataTable da.FillSchema(aDataTable, SchemaType.Source) da.Fill(aDataTable.DataSet, aDataTable.TableName) ' Create the SQL Command Builder Dim cb As New SqlClient.SqlCommandBuilder(da) cb.SetAllValues = False ' Go thru all rows and insert the data For Each r As DataRow In aDataTable.Rows ' Create the Insert-Command Dim cmdResult As New SqlClient.SqlCommand(cb.GetInsertCommand.CommandText, aConnection) cmdResult.Parameters.Clear() Dim i As Integer = 0 ' Go thru all columns in our DataTable and create a SQLParameter for our Statement with the value ' from our DataTable. For Each col As DataColumn In aDataTable.Columns i += 1 ' cmdResult.Parameters.Add("@p" & i, col.DataType).Value = r.Item(col.ColumnName) cmdResult.Parameters.AddWithValue("@p" & i, r.Item(col.ColumnName)) Next Dim iAffectedRecords As Integer = cmdResult.ExecuteNonQuery() Next End Sub
Achja, wie immer gilt, gerne darf man mir Verbesserungen, Anregungen und natürlich auch Kritik zukommen lassen.

Vielen herzlichen Dank für die Bereitstellung des Codes. Das hat meinen Tag so richtig gut gemacht!!!! Ich bin ein SQL-Server und XMl-Neuling.
Es sind die stillen Teamworker im Internet, die einem das Leben vereinfachen. Vielen, vielen Dank!!!
Hallo Susanne,
freut mich sehr, dass dir der Code geholfen hat.
Vielen Dank für dein Feedback!
Gruß,
dh