user17753
user17753

Reputation: 3161

C# -- Using multiple DataTables of the same name and namespace in a DataSet

suppose I have an MS SQL Server database table named "GROUPS" such as the following:

GROUP_ID    GROUP_NAME    DESCRIPTION
    1        Grp1            Null
    2        Grp2            Null
    3        Grp3            Test

GROUP_ID is an auto increment primary field, GROUP_NAME is a unique non-null varchar field, and Description is a null-allowed (optional) varchar field.

I am trying to produce some XML output as a web service, to be consumed by some other process, of the table information. The XML must be output in a specific manner.

The end goal would look like this:

<?xml version="1.0" encoding="utf-8"?>
<GROUPS>
    <GROUP>
        <GROUP_ID>1</GROUP_ID>
        <GROUP_NAME>Grp1</GROUP_NAME>
        <DESCRIPTION/>
    </GROUP>
    <GROUP>
        <GROUP_ID>2</GROUP_ID>
        <GROUP_NAME>Grp2</GROUP_NAME>
        <DESCRIPTION/>
    </GROUP>
    <GROUP>
        <GROUP_ID>3</GROUP_ID>
        <GROUP_NAME>Grp1</GROUP_NAME>
        <DESCRIPTION>Test</DESCRIPTION>
    </GROUP>
</GROUPS>

This procedure almost gets the desired goal:

    string sql = "SELECT * FROM GROUPS";
    Response.ContentType = "application/xml"; // Set the page to output XML
        SqlDataAdapter da = new SqlDataAdapter(sql, conn); // SQL Adapter, conn is an already open SQL connection
        DataSet ds = new DataSet("GROUPS"); // Root Node of XML doc will be "GROUPS"
        da.Fill(ds, "GROUP"); // Each record node is a "GROUP"
        XmlTextWriter xml = new XmlTextWriter(Response.Output) { Formatting = Formatting.None }; // XML writer
        xml.WriteStartDocument(); // XML header
        ds.WriteXml(xml); // Write XML output

The issue with this procedure is that it does not provide the desired empty nodes such as for null values in the table. It would look like this:

<?xml version="1.0" encoding="utf-8"?>
<GROUPS>
    <GROUP>
        <GROUP_ID>1</GROUP_ID>
        <GROUP_NAME>Grp1</GROUP_NAME>
    </GROUP>
    <GROUP>
        <GROUP_ID>2</GROUP_ID>
        <GROUP_NAME>Grp2</GROUP_NAME>
    </GROUP>
    <GROUP>
        <GROUP_ID>3</GROUP_ID>
        <GROUP_NAME>Grp1</GROUP_NAME>
        <DESCRIPTION>Test</DESCRIPTION>
    </GROUP>
</GROUPS>

After doing some research, an attempt to create the desired output was performed with the following procedure:

        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        cmd.CommandText = "SELECT * FROM GROUPS";
        SqlDataReader row = cmd.ExecuteReader();

        DataSet ds = new DataSet("GROUPS");

        while (row.Read())
        {

            DataTable table1 = new DataTable("GROUP" + row["GROUP_ID"]); // This line is the issue
            object[] columns = new object[row.FieldCount];


            for (int i = 0; i < row.FieldCount; i++)
            {

                string name = row.GetName(i);

                    table1.Columns.Add(name);
                    columns[i] = DBstr(row[i]);

            }

            table1.Rows.Add(columns);
            ds.Tables.Add(table1);

        }

        row.Close();

        Response.ContentType = "application/xml"; // Set the page to output XML
        XmlTextWriter xml = new XmlTextWriter(Response.Output) { Formatting = Formatting.None }; // XML writer
        xml.WriteStartDocument(); // XML header
        ds.WriteXml(xml, XmlWriteMode.IgnoreSchema); // Write XML output


    public static string DBstr(Object obj)
    {
        if (obj == null || obj == DBNull.Value)
        {
            return String.Empty; // Default value for null DB value
        }

        else if (obj.GetType() == typeof(DateTime))
        {
            return ((DateTime)obj).ToString("MM/dd/yyyy");
        }
        else
        {
            return obj.ToString();
        }
    }

The issue here is that I had to give either a unique name for each DataTable, or a unique namespace. Prior to writing out xml from the DataSet. So it would look something like this:

<?xml version="1.0" encoding="utf-8"?>
<GROUPS>
    <GROUP1>
        <GROUP_ID>1</GROUP_ID>
        <GROUP_NAME>Grp1</GROUP_NAME>
        <DESCRIPTION/>
    </GROUP1>
    <GROUP2>
        <GROUP_ID>2</GROUP_ID>
        <GROUP_NAME>Grp2</GROUP_NAME>
        <DESCRIPTION/>
    </GROUP2>
    <GROUP3>
        <GROUP_ID>3</GROUP_ID>
        <GROUP_NAME>Grp1</GROUP_NAME>
        <DESCRIPTION>Test</DESCRIPTION>
    </GROUP3>
</GROUPS>

Or, each GROUP row would have an xmlns tag thrown in.

Either way, undesirable. So what is the simplest way to get the desired goal using C# here?

Upvotes: 0

Views: 2157

Answers (2)

Mike Burton
Mike Burton

Reputation: 3020

Without a custom serializer I don't think you can achieve what you want. DataTable names are unique by design, and the serialization of a DataSet respects that uniqueness for the somewhat obvious reason that they have to be deserializable, meaning the names have to be unique after serialization.

Upvotes: 0

Pankaj
Pankaj

Reputation: 10095

Try to change the query

string sql = "SELECT * FROM GROUPS";

to below

string sql = "SELECT GROUP_ID, GROUP_NAME, IsNull(DESCRIPTION, '') as DESCRIPTION  FROM GROUPS";

Upvotes: 1

Related Questions