The DataSet class in .NET plays a major role by providing a disconnected
data access model. There are situations when we might not require a database
to store data. Rather, we may store the data in an XML file. Microsoft .NET
provides support for designing such applications with the help of the DataSet
class in the System.Data namespace. In this article I would like to highlight
how we can use an XML file as a repository for the CRUD
operations and the benefits of doing this. I will also show how we can search
for a specific record based on its primary key value or based on a specific
search criterion. The sample code snippets in this article have been written
in C#.
What is a DataSet?
The DataSet is the core component of the disconnected
architecture of ADO.NET that is used to cache the data read from the data
source in memory. The data stored in the memory can be modified and written
back to the data source. Hence, DataSet is known as an in-memory
representation of data. DataSets can be used with multiple and different data
sources (Database, XML file, etc.). The DataSet contains one or more DataTable
objects. DataTable object contains DataRows and DataColumns, as well as a primary
key, foreign key, and constraint and relation information about the data in the
DataTable objects. The DataTable object represents every table within a
DataSet; DataColumn object represents every column within a DataTable. The DataRow
object represents every row within a DataTable. The DataSet does not validate
the XML data against the schema; it simply uses it to infer the structure
required for the tables in the DataSet. The System.Data.DataSet class is
provided to support DataSet in .NET.
The XML-Based Methods of the DataSet class
The DataSet class has wonderful support for XML, which will
be discussed in detail in this article. The DataSet class has several methods
for reading and writing data as XML, including the following.
·
GetXml Method
·
GetXmlSchema Method
·
InferXmlSchema Method
·
WriteXml Method
·
WriteXmlSchema Method
·
ReadXml Method
·
ReadXmlSchema Method
These methods have been explained in the sections that
follow.
The GetXml Method
This method returns a string containing an XML
representation of the data stored in the DataSet. No schema is included. The
syntax of this method is as follows:
The GetXmlSchema Method
This method returns just the schema for an XML
representation of the data stored in the DataSet. The GetXmlSchema method
returns XML as a string, therefore requiring more overhead than using WriteXmlSchema
method to write XML to a file. The syntax of this method is the following.
public string GetXmlSchema();
InferXmlSchema Method
This method applies XML schema to the DataSet after taking
an XML document provided in a TextReader, XmlReader, Stream object or a
specified disk file. The syntax of overloaded versions of this method is as
follows.
public void InferXmlSchema(string,string[]);
public void InferXmlSchema(TextReader,string[]);
public void InferXmlSchema(Stream,Stream[]);
public void InferXmlSchema(XmlReader,string[]);
WriteXml Method
This method writes the XML representation of the data in the
DataSet object to a TextWriter object, an XmlWriter object, a Stream object or
directly to a specified disk file. The syntax of overloaded versions of this
method is below.
public void WriteXml(string);
public void WriteXml(TextWriter);
public void WriteXml(Stream);
public void WriteXml(XmlWriter);
This XML representation can either include or omit the
corresponding XML schema.
WriteXmlSchema Method
This method writes the XML schema of the DataSet to a
TextWriter object, an XmlWriter object, a Stream object or directly to a
specified disk file. The syntax of overloaded versions of this method is the
following.
public void WriteXmlSchema(string);
public void WriteXmlSchema(TextWriter);
public void WriteXmlSchema(Stream);
public void WriteXmlSchema(XmlWriter);
ReadXml Method
This method reads the XML data (including a schema when
present) into the DataSet from a TextReader, XmlReader, Stream object or directly
to a specified disk file. The syntax of overloaded versions of this method is below.
public void ReadXml(string);
public void ReadXml(TextReader);
public void ReadXml(Stream);
public void ReadXml(XmlReader);
ReadXmlSchema Method
This method reads the XML schema describing the contents of
the DataSet to a TextReader, XmlReader, and Stream object or directly to a
specified disk file. The syntax of overloaded versions of this method is the
following.
public void ReadXmlSchema(string);
public void ReadXmlSchema(TextReader);
public void ReadXmlSchema(Stream);
public void ReadXmlSchema(XmlReader);
The XmlWriteMode Enumeration
The WriteXml method can be used with a second parameter that
specifies XML output of data in more detail. However, the second parameter is
optional. This method accepts a value from the XmlWriteMode enumeration. The
options/value of enumeration of XmlWriteMode parameter is as follows:
·
WriteSchema
·
IgnoreSchema
·
DiffGram
The following section discusses the above in details.
Write Schema: In this mode it writes the XML data stored in
the Dataset along with the loadedschema in DataSet.
Ignore Schema: In this mode only XML data stored in the
DataSet will be written. No schema will be written or even loaded in DataSet.
This is the default mode.
DiffGram: In this mode the data is written out in a form
that includes all the original values and any current values for columns in
each row that have been modified since the DataSet was loaded. So the changes
made in the DataSet are persisted in the XML file. Sometimes we need to
transfer (XML in DiffGram format) only the changed data in a DataSet to a XML
file, then we use GetChange method of DataSet.
DataSet ChangedsProducts = new DataSet();
ChangedsProducts = dsProducts.GetChange();
ChangedsProducts.WriteXml(sPath,XmlWriteMode.DiffGram);
The XmlReadMode Enumeration
The ReadXml method creates the relational schema of the DataSet
depending on the option/value of enumeration of XmlReadMode argument specified.
The XmlReadMode enumeration specifies how to read XML data and schema into a
DataSet. This second parameter of ReadXml method is also optional. The
options/value of enumeration of XmlReadMode parameter are as follows.
·
Auto
·
Diffgram
·
Fragment
·
IgnoreSchema
·
InferSchema
·
ReadSchema
The following section discusses the above in details.
Auto: This is the Default mode. In this mode it reads and
examines the XML and chooses the most appropriate option in the following
order.
If the XML data is a DiffGram, then the value of enumeration
of XmlReadMode argument is set to DiffGram. If the dataset contains a schema
or the XML contains an in-line schema, then the value of enumeration of
XmlReadMode argument is set to ReadSchema. If the DataSet does not contain a
schema and the XML does not contain an in-line schema, then the value of
enumeration of XmlReadMode argument is set to InferSchema. It is recommended
to set an explicit value for enumeration of XmlReadMode argument, rather than
accept the Auto default. This gives the best performance if we know the format
of the XML being read.
DiffGram: In this mode the ReadXml method reads a DiffGram
and adds the data to the current schema. DiffGram merges new rows with
existing rows where the unique identifier values match.
Fragment: In this mode the ReadXml method reads the XML
documents containing inline XDR schema fragments. Fragments that match the
DataSet schema are appended to the appropriate tables. Fragments that do not
match the DataSet schema are discarded.
Ignore Schema: In this mode the ReadXml method ignores any
inline schema and loads data into the existing DataSet schema. If the data
does not match the existing schema, it is discarded. If no schema exists in
the DataSet, no data will be loaded.
Infer Schema: In this mode the ReadXml method ignores any
inline schema, infers schema from the data, and loads the data. If the DataSet
already contains a schema, the current schema is extended by adding columns to
existing tables, where they exist, or by adding new tables where there is no
existing table. An exception will be thrown if an inferred table already exists
with a different namespace or if any inferred columns conflict with existing
columns.
Read Schema: In this mode the ReadXml method reads any
inline schema and loads the data and schema. If the DataSet already contains a
schema, new tables are added from the inline schema to the existing schema
present in the DataSet. However, an exception is thrown if any tables in the
inline schema already exist in the DataSet. We will not be able to modify the
schema of an existing table using XmlReadMode.ReadSchema. If the DataSet does
not contain a schema and there is no inline schema, no data will be read.
Implementing DataSet with Xml
This section shows how we can use the DataSet with an Xml
file. Please follow the stated configuration settings that are required in the
web.config file and add the namespaces that have been mentioned.
Add the following in the web.config file.
<appSettings>
<add key = "CString" value ="Server=self-r8yilmkzvk; Database = Sanjit; User
ID=sa;Password = sa;"></add>
<add key = "ProductFile" value ="/Test/products.xml"> </add>
</appSettings>
Remember to change the above settings (Server, Database,
User ID, Password, etc.) in the web.config file as per the settings of the
system on which the code is to be executed.
Database structure
In this section I have populated the DataSet from a Sql Server
DataBase table. The following is the table structure.
Table Name: products
Column Name DataType Properties
Prod_ID Int(4)
Primary Key
Prod_Name Varchar(50)
Prod_Price Money(8)
Prod_Available Char (3)
Prod_Display Bit(1)
Writing Data from a DataSet to an XML File
This example demonstrates how to write data from a DataSet
directly to a disk file as an XML document.
Listing 1
SqlConnection conn =
new SqlConnection(ConfigurationSettings.AppSettings["CString"].ToString ());
SqlDataAdapter DA =
new SqlDataAdapter(
"select Prod_ID, Prod_Name,Prod_Price,Prod_Available,Prod_Display from products ",
conn);
conn.Open();
DataSet DS = new DataSet();
DA.Fill(DS);
DS.WriteXmlSchema(Server.MapPath("products.xml"));
DS.WriteXml(Server.MapPath("products.xml"));
Add data to XML File
This example demonstrates how to add data to an XML file.
Listing 2
dsProducts = PopulateDataSet();
DataRow newProductRow =dsProducts.Tables[0].NewRow();
newProductRow[0] = txtPID.Text;
newProductRow[1] = txtPName.Text;
newProductRow[2] = txtPPrice.Text;
newProductRow[3] = "Yes";
newProductRow[4] = "true";
dsProducts.Tables[0].Rows.Add(newProductRow);
sPath = ConfigurationSettings.AppSettings["ProductFile"];
sPath = Server.MapPath(sPath);
dsProducts.WriteXml(sPath,XmlWriteMode.WriteSchema);
Search from an XML File using DataView
This example demonstrates how to search a result using Sort
and RowFilter properties of the DataView object.
Listing 3
dsProducts = PopulateDataSet();
if(dsProducts.Tables["Products"].Rows.Count > 0)
{
dv = dsProducts.Tables[0].DefaultView;
dv.Sort = "Prod_Name";
dv.RowFilter = " Prod_Price >" +txtSearch.Text.Trim();
if (dv.Count > 0)
{
DataList1.DataSource = dv;
DataList1.DataBind();
}
}
In the above code I have used DataList control to display
the searched result. We have to write some code in the .aspx file to show the
searched result in DataList control, which is as follows:
Here I have displayed the Product Name and Product Price in
DataList control.
Listing 4
<asp:DataList id="DataList1"
style="Z-INDEX: 104; LEFT: 128px; POSITION: absolute; TOP: 8px"
runat="server"
RepeatColumns="2"
BorderStyle="None" BorderColor="#DEBA84"
BackColor="#DEBA84" CellSpacing="2"
CellPadding="3" GridLines="Both"
BorderWidth="1px">
<SelectedItemStyle Font-Bold="True" ForeColor="White"
BackColor="#738A9C"></SelectedItemStyle>
<ItemStyle ForeColor="#8C4510"
BackColor="#FFF7E7"></ItemStyle>
<ItemTemplate>
<table>
<tr>
<td>
Product Name:<%#DataBinder.Eval(Container.DataItem, "Prod_Name")%>
</td>
</tr>
<tr>
<td>
ProductPrice:<%#DataBinder.Eval(Container.DataItem, "Prod_Price")%>
</td>
</tr>
</table>
</ItemTemplate>
<FooterStyle ForeColor="#8C4510"BackColor="#F7DFB5"></FooterStyle>
<HeaderStyle Font-Bold="True"ForeColor="White" BackColor="#A55129"></HeaderStyle>
</asp:DataList>
We can also use DataGrid control or Repeter control to
display the searched result.
Refer to the code listing above. The PopulateDataSet method
populates a DataSet object from an XML File and returns the same.
Listing 5
private DataSet PopulateDataSet()
{
dsProducts =(DataSet)(Cache[ProductCacheName]);
if (dsProducts == null)
{
sPath = ConfigurationSettings.AppSettings["ProductFile"];
sPath = Server.MapPath(sPath);
if (File.Exists(sPath))
{
dsProducts = new DataSet();
dsProducts.ReadXml(sPath,XmlReadMode.ReadSchema);
Cache.Insert(ProductCacheName, dsProducts,new CacheDependency(sPath));
}
}
return dsProducts;
}
Note: Although I have populated cache object with DataSet
and made its expiration dependent upon changes to the XML file, a detail
discussion of caching is beyond the scope of this article.
We can also use the Select method of DataTable class to
search the data as shown in the previous listing.
Listing 6
DataSet dsProducts = PopulateDataSet();
DataSet.Tables["Products"].Select("Prod_Price>150","Prod_IDDESC");
Use of the GetXML Method
The following example will demonstrate the use of GetXML
method of DataSet. To read the complete XML file as a stream, we can use the GetXml
method of the DataSet class. The following code read the Products.xml file
into a DataSet and then uses the GetXml method of the DataSet class to display
the data in a TextBox.
Listing 7
sPath = ConfigurationSettings.AppSettings["ProductFile"];
sPath = Server.MapPath(sPath);
dsProducts.ReadXml(sPath);
txtXml.Text=ds.GetXml();
Delete Data from XML File
The Delete method demonstrates how to delete data from an
XML file. It takes the PID as the primary key (Prod_ID) to delete a particular
product data from the XML file.
Listing 8
private void Delete(int PID)
{
dsProducts = PopulateDataSet();
DataTable dt = new DataTable();
dt = dsProducts.Tables[0];
DataView dvProducts = new DataView();
dvProducts = dt.DefaultView;
dvProducts.Sort = "P_ID";
int rowIndex =dvProducts.Find("PID");
if (rowIndex == - 1)
{
Response.Write("Product notfound");
}
else
{
dvProducts.RowFilter = "P_ID=" +PID;
dvProducts.Delete(0);
dsProducts.WriteXml(sPath,XmlWriteMode.WriteSchema);
}
}
Edit Data in XML File
The Update method demonstrates how to update data in an XML
file. It takes the PID as Prod_ID to edit a particular product data. Here I
have edited the price of a particular product after taking the new price from
the textbox control named txtPPrice. We can also update other data of a
particular product in a similar way.
Listing 9
private void Update(int PID)
{
dsProducts = PopulateDataSet();
DataTable dt = new DataTable();
dt = dsProducts.Tables[0];
DataView dvProducts = new DataView();
dvProducts = dt.DefaultView;
dvProducts.Sort = "P_ID";
int rowIndex = dvProducts.Find(PID);
if (rowIndex == - 1)
{
Response.Write("Product notfound");
}
else
{
dvProducts.RowFilter = "P_ID=" +PID;
dvProducts[0]["P_Price"] =txtPPrice.Text;
dsProducts.WriteXml(sPath,XmlWriteMode.WriteSchema);
}
}
This section shows how we can execute the code snippets that
have been discussed so far. For this, we require the creation of objects of
the DataSet and the DataView classes. To use the DataSet class, add the
following namespaces along with the default namespaces in your application’s
code.
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Caching;
Add the following code to run the code mentioned in this
article.
DataSet dsProducts = new DataSet();
string sPath;
string ProductCacheName = "";
DataView dv=new DataView();
Suggested Readings
http://www.c-sharpcorner.com/database/dbaccess_class.asp
http://www.xmlme.com/XmlToDS.aspx?mid=45
http://msdn.microsoft.com/library/default.asp?url=/library/enus/cpguide/html/cpconxmldataset.asp
http://aspnet.4guysfromrolla.com/articles/112603-1.aspx
http://support.microsoft.com/default.aspx?scid=kb;en-us;323290
Conclusion
This article has depicted how we can use the Dataset class
to provide simple yet effective access to an XML file. This is, however,
recommended for use in only smaller applications, those with low volume of
data.
It will be useful only in the following scenarios.
·
When we are handling a small amount of data.
·
When we are developing a demo, prototype or other small
applications.
·
When the user does not need to install and maintain any
database engine.
·
When cost is a factor.
The demerit of this methodology can be attributed to memory
consumption when dealing with high volumes of data as the entire data would have
to be loaded into the memory. This would become a nightmare for large
applications and therefore, is not recommended for use in such scenarios.