2009-04-21 18 views
1

Ich weiß, es ist nicht sportlich für diese Art von Hilfe, Aber ich bin wirklich auf diesem eine Weile stecken geblieben - gerade lese ich zwei C# Bücher und arbeite jeden Tag über 9 Stunden.Importieren von XML in SQL mit C#

Okay, hier ist mein Problem: Ich habe eine WinForms C# -Anwendung, die fast abgeschlossen ist. In SQL Ich habe drei Tabellen, die wie folgt aussehen:

CREATE TABLE [dbo].[Racuni](
[BROJ] [varchar](12) NULL, 
[DATUM] [datetime] NULL, 
[TS] [datetime] NULL, 
[USER_ID] [int] NULL, 
[KASA_ID] [varchar](3) NULL, 
[TOTAL] [float] NULL, 
[STATUS] [varchar](1) NULL, 
[ARH] [varchar](max) NULL 
) ON [PRIMARY] 

Create Table "Rac_Npl" 
(br_rac Char(12) 
, kasa_id Char(3) 
, npl_id Integer 
, iznos Money); 

CREATE TABLE [dbo].[Stavke](
[br_rac] [varchar](12) NULL, 
[kasa_id] [char](3) NULL, 
[art_id] [int] NULL, 
[kol] [float] NULL, 
[mpc] [money] NULL, 
[ompc] [money] NULL) 

Und ich habe XML-Datei (en) auf der lokalen Festplatte für diese drei Tabellen importieren - sieht die XML wie folgt aus:

<?xml version="1.0" encoding="windows-1250"?> 
<transaction> 
<table name="qryRacuniSmjene"> 
<fields> 
<field name="BROJ" type="1" size="12"/> 
<field name="DATUM" type="9" size="0"/> 
<field name="TS" type="11" size="0"/> 
<field name="USER_ID" type="3" size="0"/> 
<field name="KASA_ID" type="1" size="3"/> 
<field name="TOTAL" type="8" size="4"/> 
<field name="STATUS" type="1" size="1"/> 
<field name="ARH" type="16" size="1"/> 
</fields> 
<data> 
<row> 
<![CDATA[09-0002-0001]]> 
<![CDATA[16.04.2009]]> 
<![CDATA[16.04.2009 13:23:27]]> 
<![CDATA[1]]> 
<![CDATA[001]]> 
<![CDATA[2,60]]> 
<![CDATA[D]]> 
<![CDATA[ 
    porezni broj: 000000000000 
    Zaobilaznica bb 
]]> 
</row> 
<row> 
<![CDATA[09-0002-0002]]> 
<![CDATA[16.04.2009]]> 
<![CDATA[16.04.2009 13:23:27]]> 
<![CDATA[1]]> 
<![CDATA[001]]> 
<![CDATA[2,60]]> 
<![CDATA[D]]> 
<![CDATA[ 
    porezni broj: 000000000001 
    Zaobilaznica bb 
]]> 
</row> 
</data> 
</table> 
<table name="qryRac_nplSmjene"> 
<fields> 
<field name="br_rac" type="1" size="12"/> 
<field name="kasa_id" type="1" size="3"/> 
<field name="npl_id" type="3" size="0"/> 
<field name="iznos" type="8" size="4"/> 
</fields> 
<data> 
<row> 
<![CDATA[09-0002-0001]]> 
<![CDATA[001]]> 
<![CDATA[1]]> 
<![CDATA[2,60]]> 
</row> 
<row> 
<![CDATA[09-0002-0002]]> 
<![CDATA[001]]> 
<![CDATA[1]]> 
<![CDATA[2,60]]> 
</row> 
</data> 
</table> 
<table name="qryStavkeSmjene"> 
<fields> 
<field name="br_rac" type="1" size="12"/> 
<field name="kasa_id" type="1" size="3"/> 
<field name="art_id" type="3" size="0"/> 
<field name="kol" type="6" size="0"/> 
<field name="mpc" type="8" size="4"/> 
<field name="ompc" type="8" size="4"/> 
</fields> 
<data> 
<row> 
<![CDATA[09-0002-0001]]> 
<![CDATA[001]]> 
<![CDATA[152414]]> 
<![CDATA[1,000]]> 
<![CDATA[2,60]]> 
<![CDATA[2,60]]> 
</row> 
<row> 
<![CDATA[09-0002-0001]]> 
<![CDATA[001]]> 
<![CDATA[152414]]> 
<![CDATA[1,000]]> 
<![CDATA[2,60]]> 
<![CDATA[2,60]]> 
</row> 
</data> 
</table> 
</transaction> 

Noch einmal bin ich peinlich berührt, um auf diese Weise Hilfe anzufordern, aber ich werde versuchen, StackOverflow so gut wie möglich zu unterstützen.

Antwort

2

Mehrere CDATA-Elemente werden in Implementierungen nicht konsistent unterstützt. Zum Beispiel haben Sie Probleme beim Zugriff auf ein XDocument oder über SelectNodes. Wenn Sie das Eingabeformat ändern können, das die Dinge einfacher machen würde.

Dieser Code wurde nicht getestet und es gibt keine Fehlerbehandlung oder schlechte Datenprüfung, aber es sollte Ihnen den Anfang machen. Untersuchen Sie mit XPathDocument/XPathNavigator auf Leistung und lesen Sie meine Inline-Kommentare.

class XmlCsvImport 
{ 
    public void ImportData(string xmlData, ConnectionStringSettings connectionSettings) 
    { 
     DbProviderFactory providerFactory = DbProviderFactories.GetFactory(connectionSettings.ProviderName); 

     IDbConnection connection = providerFactory.CreateConnection(); 
     connection.ConnectionString = connectionSettings.ConnectionString; 

     // TODO: Begin transaction 

     XmlDocument doc = new XmlDocument(); 
     doc.LoadXml(xmlData); 

     foreach (XmlNode tableNode in doc.SelectNodes("/transaction/table")) 
     { 
      IDbCommand command = CreatCommand(connection, tableNode); 

      foreach (XmlNode rowNode in tableNode.SelectNodes("data/row")) 
      { 
       string[] values = GetRowValues(rowNode); 

       if (values.Length != command.Parameters.Count) 
       { 
        // TODO: Log bad row 
        continue; 
       } 

       this.FillCommand(command, values); 
       command.ExecuteNonQuery(); 
      } 
     } 

     // TODO: Commit transaction 
    } 

    private IDbCommand CreatCommand(IDbConnection connection, XmlNode tableNode) 
    { 
     string tableName = tableNode.Attributes["name"].Value; 

     IDbCommand command = connection.CreateCommand(); 
     command.Connection = connection; 
     command.CommandType = CommandType.Text; 

     XmlNodeList fieldNodes = tableNode.SelectNodes("fields/field"); 

     List<string> fieldNameList = new List<string>(fieldNodes.Count); 

     foreach (XmlNode fieldNode in tableNode.SelectNodes("fields/field")) 
     { 
      string fieldName = fieldNode.Attributes["name"].Value; 
      int fieldType = Int32.Parse(fieldNode.Attributes["type"].Value); 
      int fieldSize = Int32.Parse(fieldNode.Attributes["size"].Value); 

      IDbDataParameter param = command.CreateParameter(); 
      param.ParameterName = String.Concat("@", fieldNode.Attributes["name"]); 
      param.Size = fieldSize; 
      param.DbType = (DbType)fieldType; // NOTE: this may not be so easy 
      command.Parameters.Add(param); 

      fieldNameList.Add(fieldName); 
     } 

     string[] fieldNames = fieldNameList.ToArray(); 

     StringBuilder commandBuilder = new StringBuilder(); 
     commandBuilder.AppendFormat("INSERT INTO [{0}] (", tableName); 

     string columnNames = String.Join("], [", fieldNames); 
     string paramNames = String.Join(", @", fieldNames); 

     command.CommandText = String.Concat(
      "INSERT INTO [", tableName, "] ([", 
      columnNames, 
      "]) VALUES (@", 
      paramNames, 
      ")" 
      ); 

     return command; 
    } 

    private string[] GetRowValues(XmlNode row) 
    { 
     List<string> values = new List<string>(); 

     foreach (XmlNode child in row.ChildNodes) 
     { 
      if (child.NodeType == XmlNodeType.Text || 
       child.NodeType == XmlNodeType.CDATA) 
      { 
       values.Add(child.Value); 
      } 
     } 

     return values.ToArray(); 
    } 

    private void FillCommand(IDbCommand command, string[] values) 
    { 
     for (int i = 0; i < values.Length; i++) 
     { 
      IDbDataParameter param = (IDbDataParameter)command.Parameters[i]; 
      param.Value = values[i]; // TODO: Convert to correct data type 
     } 
    } 
1

Sie können ein XPathNavigator-Objekt zum Analysieren des XML verwenden und dann ein SqlCommand-Objekt verwenden, um die Daten in die Tabellen einzufügen. Es gibt viele Codebeispiele für beide Objekte im Internet.