Do you find the Support WebCast transcripts helpful?
Let us know!
Microsoft Support WebCast
Microsoft ADO.NET: Programming ADO.NET Datasets
April 12, 2002
Note This document is based on the original spoken Support WebCast transcript. It has been edited for clarity.
Vijaya Byri: Hi, everybody. Thank you for joining us for today's Support WebCast. The topic for today's presentation is going to be ADO.NET datasets.
Going to the next slide (2), the agenda for today is a brief overview of Microsoft® .NET architecture and ADO.NET architecture. This is to just give you a startup on the main topic. We will be discussing our main topic, ADO.NET datasets, and how XML is integrated into a dataset, and we'll also be talking about typed datasets.
Moving on to our next slide (3), it's about .NET Framework. This is a representation of basic .NET Framework architecture. The .NET Framework is a programming model for the .NET platform for building, deploying, and running Web services and applications. The .NET Framework is composed of the common language runtime and the class libraries.
The common language runtime is responsible for run-time services, such as language, integration, security enforcement, and memory process and trade management. In addition, it reduces the amount of code a developer must write to turn business logic into a reusable component.
Class libraries. The base classes provide standard functionality, such as input/output, string manipulation, etc.
Data classes support persistent data management and include SQL classes for manipulating persistent data stores through a standard SQL interface. XML classes enable XML data manipulation, and XML searching and translations.
XML Web services classes support the development of lightweight distributed components, which will work even in the face of firewalls.
Web Forms include classes that enable you to rapidly develop Web GUI applications.
Microsoft Windows® Forms support a set of classes that allow you to develop Windows GUI applications, facilitating the drag-and-drop GUI development and providing a common, consistent development interface across all languages supported by the .NET Framework.
Moving on to the next slide (4), we have ADO.NET architecture. Data processing has traditionally relied primarily on a connection-based two-tier model. As data processing increasingly uses multi-tier architectures, programmers are switching to a disconnected approach to provide better scalability for their applications.
The ADO.NET components have been designed to factor data access from data manipulation. There are two central components of ADO.NET that accomplish this: the dataset and the .NET data providers. It is a set of components including the Connection, Command, DataReader, and DataAdapter objects.
The ADO.NET dataset is a core component of the disconnected architecture of ADO.NET. The dataset is explicitly designed for data access, independent of any data source.
At this point, I'll turn it over to my colleague, Manisha, who will be talking about ADO.NET datasets in depth.
Manisha Gupta: Thank you, Vijaya. Hello, everyone.
In the following slide (5), I'll be discussing the architecture of datasets, different methods of creating datasets, navigating the dataset hierarchy, as well as copying and merging a dataset.
Moving on to the next slide (6), we have dataset architecture pictorial representation. The Dataset object provides a consistent programming model that works with all current models of data storage (flat, relational, and hierarchical). It is basically a memory-resident representation of data that provides a consistent relational programming model, regardless of the data source. It consists of a collection of DataTable objects that you can relate to each other with DataRelation objects.
A dataset consists of two main collections, a DataTableCollection and a DataRelationCollection. A DataTableCollection contains all the DataTable objects in a dataset. A DataTable is defined in the System.Data namespace and represents a single table of memory-resident data. It contains a collection of columns represented by the DataColumnCollection, which defines the schema and rows of the table. It also contains a collection of rows, represented by DataRowCollection, which contains the data and the tables.
The ConstraintCollection contains both unique constraints and foreign key constrained objects for the DataTable. A dataset contains relationships in its DataRelationCollection objects. A relationship, represented by the DataRelation object, associates rows in one DataTable with rows in another DataTable.
Now, moving on to the next slide (7), I will be introducing several methods that we can use to create a dataset, which can be applied independently or in combination. We can generate a dataset using Server Explorer or Toolbox data components.
You can populate the dataset with tables of data from an existing relational data source using a DataAdapter. You can programmatically clear DataTables, DataRelations, and Constraints within a dataset, and populate the tables with data. You can load and persist the dataset components using XML. This topic, Vijaya is going to cover.
Moving on to the next slide (8), we're talking about Server Explorer and how to use it to create the dataset. You can use both Server Explorer and Toolbox by dragging and dropping the data components onto the form. On the screen, you'll see the Toolbox with the Data Components tab selected. Drag and drop a connection object to the form and configure the connection string. Drag and drop the respective data adapter to the form as well.
Similarly, under the Form Explorer, you can create a data connection and drag it onto the form. You can then expand the connection object in the Server Explorer to show tables, stored procedures, views, etc. Drag a table onto the form, it will show SQLDataAdapter. The only limitation with Server Explorer is that you can only use SQL database.
Moving on to the next slide (9), this shows how to generate a dataset. All you have to do is to click on the Data menu of the IDE and choose Generate Dataset. Upon generating the dataset, you'll see dataset 1.1, which is the default name listed next to the connection object and DataAdapter.
As we move on to the next slide (10), I'm discussing the other method to create a dataset, which is by using a DataAdapter. Interaction with existing data sources is controlled through the DataAdapter. It is used to retrieve data from a data source, and populate tables within a dataset. It's also involves changes made to the dataset back to the data source.
DataAdapter uses the connection object of the .NET data provider to connect to a data source; it uses command objects to retrieve data from, and resolve changes to, the data source.
The Fill method of the DataAdapter is used to populate a dataset. Any number of DataAdapters can be used in conjunction with a dataset. Each DataAdapter can be used to fill a DataTable object, and resolve updates back to the relevant data source.
Moving on to the next slide (11), you see some sample code that is using the DataAdapter to create a dataset. As you can see, the code does not explicitly open and close the connection. The Fill method implicitly opens the connection that the DataAdapter is using, if it finds that the connection is not already open.
If the Fill method opens the connection, it will also close the connection when fill is finished. This can simplify your code when dealing with a single operation, such as a fill or an update. However, if you're performing multiple operations that require an open connection, you can improve the performance of the replication by explicitly calling the Open method of the connection that is performing the operations against the data source, and then calling the Close method of the connection.
Moving on to our next slide (12), it is possible to programmatically create DataTables, DataRelations, and Constraints within a dataset and populate the tables with data. It can be simplified in three different steps.
The first one is to define the columns that need to be added to the Columns collection of the DataTable. You can also set one of the columns as the primary key column to apply the constraints.
Moving to the next slide (13), the second step is to add the DataColumn objects to the Columns collection of the DataTable.
Moving to the next slide (14), we add the DataTable to the Tables collection of datasets.
In the next slide (15), we have another graphical representation of two DataTables contained within a dataset, having several DataColumns and DataRows. DataTable objects are the foundation of datasets. A DataTable object represents one table of data in a dataset. You can access DataTables using the Dataset.Tables property.
As I mentioned earlier, each DataTable has a collection of DataColumn objects and a collection of DataRow objects. The collection of DataColumn objects performs the schema for one DataTable object, and a DataRow object represents one actual row of data in a DataTable.
Moving on to our next slide (16), we have some sample code that demonstrates the steps to create the dataset programmatically. First, you create an instance of the DataTable object, then define the DataColumns, after you have defined the columns, you need to add it to the Columns collection of our DataTable. You need to repeat this procedure for every column of the DataTable. You may also specify the primary key as Any.
In order to restore data, we construct a DataRow object and fill it with data, and then we can add the row in the Rows collection of our DataTable as shown in the code. Finally, we define the dataset and add the DataTable to the Tables collection of the dataset.
Moving on to the next slide (17), we're discussing the navigation in dataset. One of the primary functions of the DataRelation is to allow navigation from DataTable to another within a dataset. A DataRelation identifies matching columns in two tables of a dataset. Relationships are contained in the DataRelationCollection object of the dataset. Both the Dataset and the DataTable classes have properties to access the DataRelationCollection. The Dataset and Relations properties and the DataTables, ChildRelations, and ParentRelations properties access DataRelationCollection objects.
Modeling the relationships in the dataset has benefits like enforcing relational integrity. Propagating key updates and row deletions and data-bound controls can provide a visual representation of the relation.
Moving on to the next slide (18), DataRelation objects can be used to relate one table to another, to navigate through the tables, and to return child or parent rules from a related table. The arguments required to create a DataRelation are a name of the DataRelation being created, and an array of one or more DataColumn references to the columns that serve as the parent and child columns in the relationship.
After you've created a DataRelation, you can use it to navigate between tables and to retrieve values. Adding a DataRelation to a dataset adds, by default, a unique constraint to the parent table and a foreign key constraint to the child table. The code example on this slide creates a DataRelation using two DataTable objects in a dataset.
Moving on to the next slide (19), as I mentioned earlier in my presentation, DataRelation can be used to navigate between tables and to retrieve all the related DataRow objects in one DataTable, when given a single DataRow from a related DataTable.
In the following example, a DataRelation is established between a table of customers and a table of orders, and retrieves all the order rows for a particular customer row using DataRow.GetChildRows.
Moving on to our next slide (20), there are several methods that can be used to copy a dataset. You can create a copy of dataset, so that you can work with data without affecting the original data, or so you can work with a subset of the data from a dataset.
When copying a dataset, you can create an exact copy of the dataset including schema, data, row state information, and row versions. You can create a dataset that contains a schema from existing datasets, but only rows that have been modified. You can return all rows that have been modified or specify a specific DataRow state. Also, you can create a copy of the schema or relational structure of the dataset only, without copying any rows. Rows can be imported into an existing data table using ImportRow. I'll be going through the above methods in the following slides.
Moving on to our next slide (21), this is a method showing how to create an exact copy of the dataset. To create an exact copy of the dataset, that inserts both schema and data, use the Copy method of the dataset. The code example on the slide shows how to create an exact copy of the dataset.
Moving to the next slide (22), to create a copy of a dataset that includes schema and only the data representing added, modified, or deleted rows, use the GetChanges method of the dataset. You can also use GetChanges to return only rows with a specified row state by passing a DataRowState value when calling GetChanges. The code example on this slide shows how to pass a DataRowState when calling the GetChanges method.
Moving to the next slide (23). To create a copy of a dataset that only includes schema, use the Clone method of the dataset. You can also add existing rows to the cloned dataset using the ImportRow method of the data tables. ImportRow will add data, row states, and row version information to the specified table. Columns value will only be added when the column name matches and the data type is compatible. The code example on this slide illustrates what I just said.
Moving on to our next slide (24), we're discussing merging a dataset. Merging is typically used on a client application to incorporate the latest changes from a data source into an existing dataset. This allows the client application to have a refreshed dataset, with the latest data from the data source. You can use the Merge method of the dataset to merge the contents of the dataset, DataTable, or DataRow array into an existing dataset. The Merge method is used to merge two Dataset objects that have largely similar schemas. Merge method is typically called at the end of a series of procedures, like validating changes, reconciling errors, updating the data source with the changes, and finally refreshing the existing dataset.
If the schemas of the Dataset objects being merged are in conflict, a MergeFailed event will be raised. It usually occurs when a target and source DataRow have the same primary key value, and enforce constraints are set to true, or if the primary key columns of a table being merged differ between the tables in the two Dataset objects, an exception will be thrown and the MergeFailed event will be raised.
Arguments passed in a MergeFailed event have a Conflict property that identifies the conflict in schema between the two Dataset objects, and a Table property that identifies the name of the table in conflict.
Moving on to our next slide (25), several factors and options affect how new data is merged into an existing dataset. One of the factors is the primary key. If the table receiving new data and schema from a merge has a primary key, new rows from the incoming data are matched with existing rows that have the same original priority key values as those in the incoming data.
If incoming or existing rows have a row state of added, their primary key values are matched using the current primary key value of the added row, because no original row versions exist. If the table receiving new data from a merge does not have a primary key, new rows from the incoming data cannot be matched to existing rows in the table and are instead appended to the existing table.
While the PreserveChanges parameter of Merge method specifies whether or not to put those changes in the existing dataset, and how to handle new schema elements found in the incoming data. If PreserveChanges is true, the data from the existing row is maintained in the current row version of the existing row, while the data from the original row version of the existing row is overwritten with the data from the original row version of the incoming row.
The RowState of the existing row is set to modified. When PreserveChanges is false, both the current and original row versions in the existing row are overwritten with the data from the incoming row, and the RowState of the existing row is set to the RowState of the incoming row. If the PreserveChanges flag is not specified, it is set to false by default.
The next option is MissingSchemaAction, which is used to specify how merge will handle schema elements in the incoming data that are not part of the existing dataset. It can be used to add the new schema information to the dataset and populate the new columns with the incoming value, and this is by default; or it can be used to add the new schema and primary key information; or it can be used to throw an exception, if mismatched schema information is encountered, and ignore the new schema information.
The other factor that affects merging is the constraints. With the Merge method, constraints are not checked until all new data has been added to the existing dataset. After the data has been added, constraints are enforced on the current values in the dataset
Moving on to our next slide (26) is sample code that demonstrates the steps that you would need to do during the merge of two datasets. As you can see, resource creates instances of a Dataset and a DataTable. We then also create a variable for a temporary dataset, for example, xSet. Add the DataTable to the Tables collection of the original dataset and then add DataColumns and DataRows, if required. Next, commit all the changes made to the dataset using the AcceptChanges function. Now make a few changes to the row values or add new rows, and then check for errors, if any. Get the changes, using GetChanges method, to extract a subset and add a new column to xSet that is the new dataset which changes the schema. Finally, merge changes back to the first dataset.
From here onward, I'm going to turn it over to Vijaya to continue with the presentation. Thank you.
Vijaya: XML and datasets (slide 27). ADO.NET leverages the power of XML to provide disconnected access to data. ADO.NET was designed hand-in-hand with the XML classes in the .NET Framework. Both are components of a single architecture. ADO.NET and XML classes in the .NET Framework converge in the Dataset object. The dataset can be populated with data from an XML source, whether it is a file or an XML stream. The dataset can be written as W3C compliant XML, including its schema as XSD schema, regardless of the source of the data in the dataset.
Because the native serialization format of the dataset is XML, it is an excellent medium for moving data between tiers, making the dataset an optimal choice for remoting data and schema context to and from an XML Web service.
The dataset can also be synchronized with an XML data document to provide relational and hierarchical access to data in real time. As we're discussing how to load a dataset with XML data, how to write a dataset as XML, how to load a dataset with XSD schema, write a dataset as XSD schema, and synchronize the dataset and XMLDataDocument.
Going onto the next slide (28), loading a dataset with XML data. The method used to load XML data into a dataset is ReadXml. The slide shows two ways of reading XML, one which takes a Stream object parameter and the other which takes two parameters, Stream object and XmlReadMode.
The first type of constructor can take parameters of type Stream, which will be the location of the XML file, or the URL to the XML file, and it can take TextReader and XmlReader objects. It's the same with the second constructor in connection with these Stream objects; you can specify the XML mode in which you want to read the data.
Going on to the next slide (29), this slide shows you the sample code reading an XML file directly into a dataset. We are specifying the mode as Auto, in this case. As you can see, I'm using the DataRow objects of the dataset to print the row value to the console. What we are doing here is creating the dataset and an XMLDataDocument to which we are loading our XML file, and we are using the Dataset object in order to print out our values.
Going on to the next slide (30), we'll be talking a little bit about XmlReadMode. There are six types of modes that can be specified while reading an XML data. They are Auto, DiffGram, Fragment, IgnoreSchema, InferSchema, and ReadSchema.
Auto is a default mode if no mode is specified, performs the most appropriate actions. If the data is in DiffGram format, it sets the XmlReadMode to DiffGram. If the dataset already has a schema, or the data contains an inline schema, then the mode is set to ReadSchema. If the dataset does not already have a schema and the document does not contain an inline schema, the ReadMode is set to InferSchema.
DiffGram mode. What is a DiffGram? A DiffGram is an XML file that has the original and modified values for all the rows. The dataset reads a DiffGram, applying changes from the DiffGram to the dataset. The semantics are identical to those of a merge operation. As with the merge operation, RowState values are preserved. Input to ReadXml with DiffGrams should only be obtained using the output from WriteXml as a DiffGram.
The target dataset must have the same schema as the dataset on which WriteXml as a DiffGram is called, otherwise the DiffGram merge operations fails and an exception is thrown.
Fragment. Fragment reads XML documents, such as those generated by executing far XML queries against an instance of SQL Server™. When XmlReadMode is set to Fragment, the default namespace is read as the inline schema.
IgnoreSchema ignores any inline schema and reads data into the existing dataset schema. If any data does not match the existing schema, it is discarded. If the data is a DiffGram, IgnoreSchema has the same functionality as DiffGram.
InferSchema. InferSchema ignores any inline schema. InferSchema from the data end loads the data. If the dataset already contains a schema, the current schema is extended by adding new tables, and adding columns to existing tables. An exception is thrown if the InferTable already exists, but with a different namespace, or if any of the inferred columns conflict with existing columns.
ReadSchema reads any inline schema and loads the data. If the dataset already contains schema, new tables may be added to the schema, but an exception is thrown if any tables in the inline schema already exist in the dataset.
Going to the next slide (31), writing a dataset as XML. This method writes XML data and, optionally, the schema from the dataset. The method used to write XML data is WriteXml method. The slide shows two ways of writing XML data. Typically the WriteXml can take one or two parameters.
The first method can take a Stream, a String, a TextWriter, or an XMLWriter object. The String in this case would be a location to the XML file or a URL to the XML file.
The second method (where we pass two parameters), in place of Stream, we can have String, TextWriter, or XmlWriter, along with the XmlWriteMode. The following slide (32), shows the sample code for writing XML data using a Dataset object. As we can see, initially the data is gotten from the Northwind database, fills the dataset, and then writes the XML data to a file on the local disk as Customers.xml. The WriteMode was similar that of XmlReadModes. We have, in this case, only three modes: DiffGram, IgnoreSchema, and WriteSchema.
DiffGram writes the entire dataset as a DiffGram, including original and current values, to generate a DiffGram containing only changed values, call GetChanges and then call WriteXml as a DiffGram on the return to data set.
IgnoreSchema writes the current contents of the dataset as XML data, without an XSD schema. If no data is loaded into the dataset, nothing is written.
WriteSchema, if this is the default, writes the current contents of the dataset as XML data, with the relational structure as inline XSD schema. If the dataset has only a schema with no data, only the inline schema is written. If the dataset does not have a current schema, nothing is written.
Loading a dataset with the XSD schema (slide 33). To load the schema of a dataset from an XML document without loading any data, you can use the ReadXmlSchema method of the dataset. ReadXmlSchema creates dataset schema defined using XML Schema Definition Language schema.
The ReadXml method takes a single argument for a file name, a stream, or an XML reader, containing the XML document to be loaded. The XML document can contain only schema or it can contain schema inline with XML elements containing data. If the XML document passed to read XML schema contains no inline schema information, ReadXmlSchema will infer the schema from the elements in the XML document. If the dataset already contains a schema, the current schema will be extended by adding new columns to existing tables, and adding new tables if they do not already exist.
If a column being added already exists in the dataset, but has an incompatible type with a column found in the XML, an exception will be thrown. While ReadXmlSchema loads or infers only the schema of a dataset, the ReadXml method of the dataset will load or infer both the schema and the data contained in the XML document.
InferXmlSchema. You can also instruct the dataset to infer its schema from an XML document using the InferXmlSchema method of the dataset. InferXmlSchema functions the same as both the ReadXml within XmlReadMode of InferSchema, and the ReadXmlSchema, if the document being read contains no inline schema. However, InferXmlSchema provides the additional capability of allowing you to specify particular XML namespaces to be ignored, in which case the schema is inferred.
InferXmlSchema takes two required arguments: the location of the XML document (specified by a file name, a stream, or an XML reader) and a string array of XML namespaces to be ignored by the operation.
Writing a dataset as XsdSchema (slide 34). To write the schema of a dataset as XmlSchema to a file, a stream, or an XML Writer, use the WriteXmlSchema method of the dataset. WriteXmlSchema takes one parameter that specifies the destination of the resulting XML schema.
The code specified in the slide shows you how we can use the GetXmlSchema method to get this into a string variable. To obtain schema of a dataset and write it as an XmlSchema string, you should use the GetXmlSchema method.
Synchronizing the dataset and XmlDataDocument (slide 35). In this section, we'll be focusing on how to synchronize a dataset and XmlDataDocument, and how to execute XPath queries and perform XSLT transformations.
The ADO.NET dataset provides you with a relational representation of data. For hierarchical data access, you can use the XML classes available in the .NET Framework. Historically, these two representations of data have been used separately. However, the .NET Framework enables synchronous access to both the relational and hierarchical representations of the data, but through the Dataset object and the XmlDataDocument object respectively.
When a dataset is synchronized with an XmlDataDocument, both objects are working with a single set of data. This means that if a change is made to the dataset, the change will be reflected in the XmlDataDocument and vice versa. The relationship between the dataset and the XmlDataDocument creates great flexibility by allowing a single application, using a single set of data to access the entire suite of services built around the dataset, as well as the XML services including XSL, XSLT, and XPath language. You do not have to choose which set of services to target the application, both are available.
There are several ways in which you can synchronize a dataset with an XmlDataDocument (slide 36). You can populate a dataset with the schema from a database and data, and then synchronize it with a new XmlDataDocument. This provides a hierarchical view of existing relational data.
Populate a dataset with schema only, synchronize it with an XmlDataDocument, and then load the XmlDataDocument from an XmlDocument. This provides a relational view of the existing hierarchical data. The table names and column names in the dataset schema must match the names of the XML elements that you want them to synchronize with. This matching is case-sensitive. The code sample in the slide shows this kind of synchronization. As you will notice, first we fill the dataset, and then create a new XmlDataDocument by passing the dataset as parameters. You cannot load an XmlDataDocument if it is synchronized with the dataset that contains data; an exception will be thrown.
Create a new XmlDataDocument, load it from an XML document, and then access the relational view of the data using the Dataset property of the XmlDataDocument. You will need to set the schema of the dataset before you'll be able to view any of the data in the XmlDataDocument using the dataset. Again, the table names and column names in your dataset schema must match the names of the XML elements that you want them synchronized with. This matching is case-sensitive.
When synchronizing the dataset with an XmlDataDocument, results may differ, depending on whether or not your DataRelation objects are nested. If you do not set the nested property to true, the resulting XML contains tables one below the other, if the dataset contains more than one table. If the nested property is set to true, you can see the hierarchy of the data.
Performing XPath queries on a dataset (slide 37). To execute XPath queries on a dataset, first the dataset needs to be synchronized with the XmlDataDocument, then you can perform the XPath queries on the XmlDataDocument. The sample code shows how to execute an XPath query on an XmlDataDocument.
Performing XSLT transformations on the dataset (slide 38). To transform a dataset using XSLT, the dataset must be synchronized with an XmlDataDocument, and then the XslTransform object can be used to perform the transformation. The sample shows how to transform an XmlDataDocument. In this case, to perform the transformation, you have to create a Navigator, which would be a parameter for the XmlTransform object, and through this, the data is transformed to the specified XSLT format.
Typed datasets (slide 39). What are typed datasets? The Dataset object provides access to data through strongly typed metaphors. Tables and columns that are part of the dataset can be accessed using user-friendly names and strongly typed variables. A typed dataset is a class that derives from the dataset, and as such it inherits all the methods, events, and properties of the dataset. Additionally, a typed dataset provides strongly typed methods, events, and properties. This means that you can access tables and columns by name, instead of using collection-based methods.
Aside from the improved readability of the code, a typed dataset also allows the Visual Studio® .NET Code Editor to automatically complete lines as you type.
Additionally, the strongly typed dataset provides access to values as the correct type at compile time. With a strongly typed dataset, type mismatch errors are caught, and then the code is compiled, rather than at runtime. The strongly typed dataset is, in essence, a bunch of wrappers to the dataset itself.
In this section, we'll see how to generate a typed dataset and how to use annotations. There are two ways to generate a typed dataset: using MSdatasetGenerator and .NET Framework command-line tools.
Using MSdatasetGenerator (slide 40). Using this tool, the dataset can be generated within a project. Building the project, the .vb class or .cs class is generated with the same name as the XSD, and the corresponding library also gets created at run time.
For creating a typed dataset, first we need an XmlSchema file. The first figure shows the schema of Orders table, which has one column named OrderId. When you open an XSD file in Visual Studio .NET, this is how it looks in pictorial format. After we have the XSD file, we need a tool to generate the dataset built on this schema. This can be done by specifying certain properties on the XSD schema.
The second picture shows the selected object as Order.xsd, and the properties that are set. As you can see, three properties are set: Build Action, Custom Tool, and Custom Tool Namespace. The Build Action should always be set to Embedded Resource, because in this case, we are using an external tool. This tool information is available in the registry. Then we specify the tool name in Custom Tool property and, finally, we specify the Custom Tool Namespace. This will be the namespace for our new library that is going to be generated. Then, build a project and you can see that in the \bin folder, the new class is created and the library for this class will be generated at run time.
This slide (41) shows the picture of the ID, where you can see how we can use the actual table name, instead of the Tables collection of the dataset. There is an advantage where, instead of remembering all of the column names and the table names, this gives you the IntelliSense® to select the column that is available in the dataset.
This slide (42) also shows the IntelliSense that we get for the typed dataset. In this case, it shows how we can add rows without using the rows collection.
Using .NET command-line tools (slide 43). This process is a two-step process. As always, we need an XSD input file, which will be one of the parameters for the Xsd.exe. The Xsd.exe generates a dataset, depending upon the input XSD file.
The slide shows the sample command-line syntax for generating a dataset. In the sample, we are using Microsoft Visual C#™ as the language compiler; different languages can be specified. We need to be using the same language compiler in order to compile the library. The language compiler, in this case we used CSC, since it's a C# language, we have specified in the Xsd.exe. We use the C# language compiler to generate the library.
To use the typed dataset that we generated using this tool, a reference should be added to this library in the application that we are going to use.
As I mentioned before, a class will be generated that has the wrapper classes further tied to dataset. For example, Class1.vb or Class1.c is the virtual language that we have used in order to generate data.
This class (slide 44) consists of the namespace and the following classes: The slide shows x, xDataTable, xRow, and xRowChangeEvent. In this case, x represents the XSD schema name. If our schema name is orders, we would be getting the classes as others, ordersDataTable, ordersRow, and ordersRowChangeEvent.
Using annotations with a typed dataset (slide 45). Annotations enable you to modify the names of the elements in your typed dataset, without modifying the underlying schema. Modifying the names of the elements in your underlying schema would cause the typed dataset to refer to objects that do not exist in the data source, and would also lose a reference to the objects that do not exist in the data source.
Using annotations, you can customize the names of objects in your typed dataset with more meaningful names, making code more readable and your typed dataset easier for clients to use. By leaving underlying schema intact, for example, the schema element for the Customers table for the Northwind database would result in a DataRow object named CustomersRow and a DataRow collection named Customers.
To add an annotation, first add the annotation namespace and then add the annotation itself. The slide shows the namespace and a sample annotation that we are going to add. The namespace that is required to use is urn:schemas-microsoft-com:xml-msprop.
There are five different types of annotations (slide 46): typedName, typedPlural, typedParent, typedChildren, and nullValue.
The typedName would change the name of the object, and typedPlural would change the name of the collection of objects. Previously, we have seen that the name would be, like, Customers, for a collection of rows. We can change it to something like Customers Rows, which is more meaningful just than saying Customers.
The other one is typedParent, which is the name of the object when referred to in a parent relationship and typedChildren is the name of the method to return objects from a child relationship. The nullValue is the underlying value of DBNull, it can change the nullValue annotation as well. All these changes should be specified in the XSD schema.
The XSD schema has the namespace for the annotations and the annotation itself, which needs to be changed so that the typed dataset reflects these changes, and you can see them in the IntelliSense.
Thank you, everybody, for joining us today.
Jason: Thanks for the presentation. I have just a couple of quick notes before we move on to the Q&A portion of this Support WebCast. If some of the details on this PowerPoint® slides were difficult to view in your browser, or you'd simply like to have a copy of the slides, be sure you download the file from the Web site. This content will be available from the Past Support WebCast page. To access this information, including details on the upcoming Support WebCasts, an easy-to-remember URL is http://support.microsoft.com/webcasts/.
The Q&A portion of the Support WebCast is intended to encourage further discussion of the Support WebCast topic. One-on-one product support issues are outside the scope of what we're able to address here today, so if you need technical assistance, please submit an incident on the Web or call Microsoft Product Support Services and speak to a Support Professional.
The first question I have, I believe it concerns, Manisha, some things you went over on your slide: While the technique you used to illustrate, illustrated to address TableRow and column values, do these not have a detrimental effect on performance? They're saying 2,000 versus 200-300 ticks per access? Is that something that you're aware of, are there problems with performance when you do this?
Manisha: I don't know if that could be a problem, but I can confirm it and maybe follow up with this one.
{Editor's note: The customer did not provide additional information at the time we released the transcript. If updates become available, we will update the transcript on the Past WebCast page.}
Jason: Okay. Next question: When we create a dataset with an object in it, e.g., color as a form property, write it as XML, then try to reload the XML into a dataset, it no longer is an object. Is it possible to do this without first serializing the object?
Manisha: In this case, after you have converted to an XML data, you need to serialize into the object again. After you have loaded the object into the dataset and got XML data from there, in order to get the object back from the XML data, you need to serialize it.
Jason: Okay. Thanks for that. Can the XML dataset hold on to all SQL data types?
Manisha: Do you mean the dataset? Yes. Well, as we mentioned before, the dataset is completely client side. All the data types that are loaded on to the dataset will be converted into the ADO.NET format data types. As far as I know, most of the data types are supported.
Jason: The next question: To create a strongly typed dataset, do you always have to start with the XSD, or can you use the dataset design tools, drag and drop?
Manisha: No, you can actually create an XSD in the project itself and change the properties, and create a typed dataset. As I mentioned, it should start off with an XSD. You should have an XSD. It can be created prior to that or you can have them created in your project, or you can use your dataset to generate an XSD file, which in turn you can use in the project.
Jason: Next question: What are the performance implications of using typed datasets?
Manisha: Because they inherit it from the Dataset object itself, there could be a little bit of a performance hit on this, but it should not be that significant, unless it's a very huge dataset.
Jason: Is there a sample code library for ADO.NET?
Vijaya: I don't think so. There isn't any code for ADO.NET, only compiled code will be available.
Manisha: The libraries that come with.NET Framework, those other ones, they will be available and you can inherit from them or overwrite some of the methods of all the objects. I doubt that code will be available for you, at least on the installed product; you should not have the code.
Jason: Can you recommend any books on this topic?
Vijaya: Yes. For ADO.NET, there are a couple of books: Microsoft ADO.NET Step by Step by Microsoft Press (ISBN 0-7356-1236-6) and Professional ADO.NET Programming by Wrox Press (ISBN: 186100527X). If you are a beginner, you can start off with the Microsoft ADO.NET Step by Step. If you know something about ADO and ADO.NET, then Professional ADO.NET Programming is a little bit more advanced and you can use that. It's from Wrox Press.
You can find a lot of samples if you go to msdn.microsoft.com and you can also go to www.gotdotnet.com. We have some pretty good samples for all the ADO.NET.
Jason: Great. Thanks for that. Can you compare dataset versus DataReader, if my application needs to support 10,000 concurrent users?
Vijaya: {Editor's note: The first part of this answer has been deleted because Vijaya began talking about XmlReader, stopped, and then corrected herself. The spoken transcript still contains the text that was removed for the clarity of this document.}
A DataReader, as I mentioned, it's only a Reader object, and you can read the data rows one after the other, and it's not memory resident; it reads one at a time. If you have a connection open on a DataReader, you can see that the connection is always busy with this DataReader, unless you close the DataReader.
Jason: This is a follow up to an earlier question concerning, I believe, the strongly typed dataset starting with XSD. The follow-up question says: Is there better performance using a generic dataset versus a strongly typed dataset?
Vijaya: As I mentioned before, when using a typed dataset it's going to inherit all the properties from the dataset class. In either way, we are going to use just one class. Other than the typed dataset class has more properties and methods, it should not give you so much of performance problems. I, myself, haven't tested the performance, like how much performance difference will be there, but as far as I understood, there is not much difference at all.
Jason: Does MTS work in this environment?
Vijaya: MTS?
Jason: Yes.
Vijaya: If your COM components are registered in MTS, through COM interoperability, you can use those components in your .NET Framework.
Jason: What is the code to call legacy ADO, if I want to use a record set?
Manisha: We can use the interop to access ADO from .NET applications. Using COM interop can address the issue.
Vijaya: Yes, you have to set a reference to the Microsoft ActiveX® Data Objects Library, and you can use the legacy ADO in .NET applications, but the minimum requirement is MDAC 2.6 and later.
Jason: What is the best way to load a large amount of data into a database from the Web? I have named an XML that is over 20 MB that I need to load. Should I use DataBind or maybe I should look for some other approach?
Vijaya: When you are loading data from a Web site, instead of binding directly to any other control, I would suggest that you first get the whole complete data, or get chunk by chunk data, and represent it in whatever form you prefer. To get the remote data, the best way would be to get a dataset or in the form of XML, because that would be a text format, which is easier to download.
Jason: How can I test a DS to see if it is empty?
Vijaya: You mean, it's not set?
Manisha: When you create a dataset, it is empty unless you add data columns into the data table. Basically, it is empty the moment you create an instance of the dataset. I don't know if that's what the question is about.
Jason: If we didn't answer that user's question, we can certainly follow up, if that user just wants to send us more information about what they're looking for.
This is also a follow up. I believe this is to the dataset versus DataReader question. It was mentioned that dataset is created at client site, in Web App it would typically be where the Web server is running. If I have 10,000 users, 10,000 datasets are created at the Web server. Does this affect performance significantly?
Vijaya: If it's a huge dataset, for each user you're going to create an instance of the dataset. I don't expect 10,000 users to access this particular feature at the same second, but there could be a couple of seconds of difference between one user and another user hitting the same site, but it should not affect it, since the dataset stores the data in XML format. So you should not see any problems with that.
Jason: At this point we have run through all of the questions that were submitted today, so I think we're going to go ahead and close out our session. I want to thank everybody for coming in and taking a listen to our presentation today. I hope the information was useful to you. Thanks to Vijaya and Manisha, for coming out today and answering some great questions.
Again, I'd like to get some feedback concerning this WebCast or other WebCasts you might have seen. What we're looking for here is, what did you think of our presentation, what did you think of the sound quality, the information that was presented, did your questions get answered during the Q&A, and are there topics you'd like to see covered in the future?
Specifically today, I'm also looking for feedback about times you'd like to see for these WebCasts. We've typically been doing these at 10:00 A.M. Pacific time, and we are thinking about expanding to, and we have already started actually, doing WebCasts at 8:00 A.M. and at 4:00 P.M., and those are both Pacific time. Let us know what you think of those times. Do you like a late WebCast, would you prefer something later in the afternoon, or do you like an early morning WebCast, are you on the East Coast and like to hit the WebCast about 11:00 A.M.?
We're open to changing this program as you want us to, because this is obviously for you, so please send us feedback on what you think about those times, as well as general feedback about times you'd like to see the WebCast, because we can certainly tailor it to the audience needs.
Again, we look forward to seeing you again in the near future. Thanks. Goodbye.