1

I'm working on a project in C# that converts a database table to an XML-file with base64 encoded contents. Please bear with me, because C# is not my day-to-day programming language.

The code I've managed to come up with is this:

OdbcCommand DbCommand = DbConnection.CreateCommand();
DbCommand.CommandText = "SELECT * FROM " + dbTable;
OdbcDataReader DbReader = DbCommand.ExecuteReader();

int fCount = DbReader.FieldCount;
string[] colnames = new string[fCount];

output += "<" + dbTable + ">\n";

for (int i = 0; i < fCount; i++)
{
    string fName = DbReader.GetName(i);
    colnames[i] = fName.ToString();
}

while (DbReader.Read())
{
    output += "\t<export_row>\n";
    for (int i = 0; i < fCount; i++)
    {
        string col = "";
        try
        {
            col = DbReader.GetString(i);
        }
        catch (Exception) { }

                        
        if (col.ToString().Length > 0 || i == 0)
        {
            output += "\t\t<" + colnames[i] + ">" + Base64Encode(col).ToString() + "</" + colnames[i] + ">\n"; ;
        }
    }
                    
    output += "\t</export_row>\n";
}

output += "</" + dbTable + ">\n";

The problem is, that even with a relatively small table, this causes the application to choke up and run extremely slowly. The obvious clue is that there's an enormous amount of iterations involved for each row, so I have been looking for a solution to this problem. I have tried using a DataSet, which seemed to increase performance slightly, but not significantly enough.

connection.Open();
adapter.Fill(dataSet);

output += "<" + dbTable + ">\n";
foreach (DataTable table in dataSet.Tables)
{
    foreach (DataRow row in table.Rows)
    {
        output += "\t<export_row>\n";
        foreach (DataColumn column in table.Columns)
        {
            output += "\t\t<" + column.ToString() + ">" + Base64Encode(row[column].ToString()).ToString() + "</" + column.ToString() + ">\n"; ;
        }
        output += "\t</export_row>\n";
    }
}
output += "</" + dbTable + ">\n";

However, the problem remains that there is no other way than iterating through all the columns each and every time. Which begs the question: isn't there a more efficient way to do this? I'm not going to make a model for every table, because there are hundreds of tables in this database and the power would be the flexibility of transferring data in this way.

Can someone help me out, or point me in the right direction? For example, is there a way to extract both the column and the value at the same time? As in: foreach(row as key => value) or something. That would drastically reduce the amount of iterations required.

Thanks in advance for thinking along! There must be something (obvious) I missed.

Yun
  • 3,056
  • 6
  • 9
  • 28
Edwin Dijk
  • 68
  • 6
  • 2
    Look at the DataSet's `GetXML()` and `WriteXML()` methods. https://learn.microsoft.com/en-us/visualstudio/data-tools/save-a-dataset-as-xml?view=vs-2019 – HardCode Sep 14 '21 at 16:00
  • 2
    Writing XML yourself is not the right way to go. C# has many XML functions including directly transforming DataSet into XML. – eglease Sep 14 '21 at 16:03
  • See https://stackoverflow.com/questions/16768263/generate-xml-using-c-sharp-from-sql-server-data – eglease Sep 14 '21 at 16:04
  • 5
    You should also use a `StringBuilder`, I'm sure that would help. – DavidG Sep 14 '21 at 16:08
  • Another good example https://www.c-sharpcorner.com/UploadFile/deepak.sharma00/how-to-write-data-of-an-sql-server-table-to-an-xml-file-usin/ – eglease Sep 14 '21 at 16:11
  • 1
    Which DBMS exactly do you use? Some have built-in XML creation capabilities. See [FOR XML](https://learn.microsoft.com/en-us/sql/relational-databases/xml/for-xml-sql-server?view=sql-server-ver15) in Sql Server. – Alexander Petrov Sep 14 '21 at 19:37

1 Answers1

1

The key is always not to write formatting of text formats yourself be it HTML, JSON, XML, YAML, or anything else. This is just asking for hard-to-find bugs and injections since you do not have control of the data or table names. For example, what happens if your data contains !, <, or >?

C# has numerous built-in XML tools and so does SQL where the formatting is done for you. Which one to use would depend on your other requirements or preferences.

    string cmd = "SELECT * FROM " + myTable + " FOR XML AUTO";
    
    using (SqlCommand k = new SqlCommand(cmd, c))
    {
        c.Open();
    
        XmlReader xml = k.ExecuteXmlReader();
    
        Console.WriteLine(xml);
    
        c.Close();
    }
    string ConString = "your connection string";
    string CmdString = "SELECT * FROM " + myTable;
    SqlConnection con;
    SqlCommand cmd;
    SqlDataAdapter sda;
    DataTable dt;
    using (con = new SqlConnection(ConString))
    {
        cmd = new SqlCommand(CmdString, con);
        con.Open();
        dt = new DataTable(tableName);
        sda = new SqlDataAdapter(cmd);
        sda.Fill(dt);
        dt.WriteXml(tableName + ".xml");
        con.Close();
    }
    // Create a DataSet with one table containing
    // two columns and 10 rows.
    DataSet dataSet = new DataSet("dataSet");
    DataTable table = dataSet.Tables.Add("Items");
    table.Columns.Add("id", typeof(int));
    table.Columns.Add("Item", typeof(string));

    // Add ten rows.

    DataRow row;
    
    for(int i = 0; i <10;i++)
    {
        row = table.NewRow();
        row["id"]= i;
        row["Item"]= "Item" + i;
        table.Rows.Add(row);
    }
    
    // Display the DataSet contents as XML.
    Console.WriteLine(dataSet.GetXml());
eglease
  • 2,445
  • 11
  • 18
  • 28
  • Thanks for commenting! I completely agree with your statement that generating XML yourself is not usually the best solution. So far DataSet.GetXml() seems to fit the bill almost perfectly. The problem I'm facing is that I need the data base64 encoded, because I will also be including file contents (like images) and I want to be sure there is nothing that breaks the XML, or rather, nothing that breaks the XML reader on the other end of the data transfer. I have been trying to get it base64 encoded out of the database, to no avail. Is there any way you know of, that would work in this scenario? – Edwin Dijk Sep 15 '21 at 07:33
  • I never tried base64 encoding with CML but there are lots of examples. Check out https://stackoverflow.com/questions/17835928/write-xml-in-base64-encoding and https://stackoverflow.com/questions/23498426/base-64-encoding-xml-to-post-to-webservice. As far as checking XML for correctness. I have used XSDs before and they work great https://stackoverflow.com/questions/751511/validating-an-xml-against-referenced-xsd-in-c-sharp but I had a specific document to validate. You might want to post another question on SO if you run into issues. – eglease Sep 15 '21 at 13:45
  • 1
    Thanks for replying! In the end I decided to change the receiving end of the software to be able to use your suggestion. I still use the "old" method for the base64 encoded images, but with some changes to the queries and a separate method for sending this data, I got it to work just fine. I'm really happy with the enormous performance increase. Thanks! – Edwin Dijk Sep 23 '21 at 10:52