Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 12 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
12
Dung lượng
296,15 KB
Nội dung
107 Chapter 7 SavingandRestoringData After completing this chapter, you will be able to: Export a DataSet to a file in XML format Import a previously exported DataSet from XML format Define the structure of the exported XML content Access the XSD schema for a DataSet or DataTable ADO.NET isn’t the only popular format for managing data in .NET applications. XML—content crafted using the Extensible Markup Language—is another common format that provides standardized, cross-platform data management in a semi-human-readable format. The DataSet class and the DataTable instances contained within it include features for moving data back and forth between ADO.NET and XML. This chapter demonstrates those features, focusing on the ability to serialize the contents of a DataSet for later use, either by loading it into another DataSet or by accessing the data directly through some other XML-enabled application. ADO.NET includes full schema definition support using Schema Definition Language (XSD). Note Before version 4, ADO.NET included an XmlDataDocument class that supported on-demand synchronization between the contents of a DataSet and an XML document. That class has since been deprecated. You can simulate some of the functionality formerly available through XmlDataDocument using the features discussed in this chapter. You can also use DataSet–focused LINQ queries, as discussed in Chapter 18, “Using LINQ to DataSet,” as a substitute for the obso- lete XmlDataDocument class. Serializing DataSet and DataTable Objects ADO.NET was designed with XML in mind, so generating XML content from a DataSet takes very little effort. Reading XML content into a DataSet is even easier because ADO.NET will guess at the correct structure of the data even if you don’t provide table design guidance. Dwonloaded from: iDATA.ws 108 Microsoft ADO.NET 4 Step by Step Writing XML To generate XML for the data content of an existing DataSet instance, call its WriteXml method, passing an output file name. C# DataSet infoSet = new DataSet(); // ----- Add tables, relations, and data, then call . infoSet.WriteXml(@"c:\StorageFile.xml"); Visual Basic Dim infoSet As New DataSet ' ----- Add tables, relations, and data, then call . infoSet.WriteXml("c:\StorageFile.xml") In addition to file names, various overloads of WriteXml accept a valid Stream instance, a TextWriter instance, or an XmlWriter instance as their first argument. The generated XML is straightforward, using table and column names to define each element tag. Here is some typical XML data content produced by WriteXml. This content includes three customer data rows, each with four fields: a string column (BusinessName), two numeric fields (ID, AnnualFee), and a date value (ContractDate) in UTC format with a time zone offset. <CustomerDataSet> <Customer> <ID>1</ID> <BusinessName>City Power & Light</BusinessName> <AnnualFee>500</AnnualFee> <ContractDate>2008-06-01T00:00:00-07:00</ContractDate> </Customer> <Customer> <ID>2</ID> <BusinessName>Lucerne Publishing</BusinessName> <AnnualFee>300</AnnualFee> <ContractDate>2008-01-01T00:00:00-08:00</ContractDate> </Customer> <Customer> <ID>3</ID> <BusinessName>Southridge Video</BusinessName> <AnnualFee>350</AnnualFee> <ContractDate>2010-02-15T00:00:00-08:00</ContractDate> </Customer> </CustomerDataSet> Dwonloaded from: iDATA.ws Chapter 7 SavingandRestoringData 109 By default, WriteXml writes XML for only the data rows in each table; the method saves no information about the structure of the DataSet. To include the DataSet object’s schema defi- nition along with the data, add a second argument to the WriteXml method call, passing XmlWriteMode.WriteSchema. C# infoSet.WriteXml(targetFile, XmlWriteMode.WriteSchema); Visual Basic infoSet.WriteXml(targetFile, XmlWriteMode.WriteSchema) Other XmlWriteMode enumeration members include IgnoreSchema (don’t include the schema, which is the same as leaving off the second argument) and DiffGram (a special format that outputs differences between the Original and the Current versions of each DataRow within the DataSet). If you want to output only the schema, use the DataSet object’s WriteXmlSchema method, passing it a file name, a Stream, a TextWriter, or an XmlWriter. C# infoSet.WriteXmlSchema(targetSchemaFile); Visual Basic infoSet.WriteXmlSchema(targetSchemaFile) The DataTable class also includes WriteXml and WriteXmlSchema methods that you can use to generate XML content on a table-by-table basis. In addition to the file/stream/writer tar- get and the XmlWriteMode arguments, the DataTable versions of these methods accept an optional Boolean argument that indicates whether child tables linked via DataRelation ob- jects should be sent to the output with the instantiating table’s schema or data. You can use this Boolean argument either after or instead of the XmlWriteMode argument. C# // ----- Write the customer dataAND the linked order data. customers.WriteXml(targetFile, true); Visual Basic ' ----- Write the customer dataAND the linked order data. customers.WriteXml(targetFile, True) Dwonloaded from: iDATA.ws 110 Microsoft ADO.NET 4 Step by Step If you want to keep the XML content in the application, the DataSet class includes GetXml and GetXmlSchema methods that return string documents with content similar to the output of the WriteXml and WriteXmlSchema methods. The DataTable.GetDataTableSchema method returns the XSD for a table in plain string format. Reading XML Both the DataSet and DataTable classes include ReadXml and ReadXmlSchema counterparts to the XML-writing methods. To use them, create a new DataSet or DataTable instance; then call the appropriate method, passing a file name, a Stream, a TextReader, or an XmlReader. C# DataSet infoSet = new DataSet(); // ----- To read the schema, use . infoSet.ReadXmlSchema(@"c:\StorageSchemaFile.xml"); // ----- To read the data, use . infoSet.ReadXml(@"c:\StorageFile.xml"); Visual Basic Dim infoSet As New DataSet ' ----- To read the schema, use . infoSet.ReadXmlSchema("c:\StorageSchemaFile.xml") ' ----- To read the data, use . infoSet.ReadXml("c:\StorageFile.xml") A second argument to the DataSet.ReadXml method lets you indicate how the incoming content should be processed. It uses one of the following enumerated values: XmlReadMode.Auto Lets ReadXml figure out what to do with the incoming content automatically. If it detects a valid schema with the data, it processes the schema before loading the data. If it sees a DiffGram, it interprets it appropriately. This is the default option if you don’t add the read-mode argument. XmlReadMode.ReadSchema Reconstructs the DataTable members of the DataSet without loading in the data. Dwonloaded from: iDATA.ws Chapter 7 SavingandRestoringData 111 XmlReadMode.IgnoreSchema Loads in the data, ignoring any schema that might be included in the XML. Instead, the existing DataSet structure is used. XmlReadMode.InferSchema Builds a new schema based on the structure of the XML data alone, ignoring any included schema. If needed, any existing DataSet structure will be augmented with new schema information. XmlReadMode.DiffGram Reads in the content previously written with the WriteXml method’s XmlWriteMode.DiffGram mode. XmlReadMode.Fragment Reads in and processes XML content that might be partial or incomplete. XmlReadMode.InferTypedSchema Similar to the InferSchema mode, but ReadXml will go out of its way to figure out the data type of each incoming data column. ReadXml or ReadXmlSchema support both inline and linked XSD structure definitions. DataSet includes an additional InferXmlSchema method. It works just like the ReadXmlSchema method, but you can pass it an array of namespace names to exclude on import. Guiding XML Generation The Read . and Write . XML methods generate valid XML that can be used right away with any XML tools. Still, the default format might be insufficient for your processing needs. That’s why ADO.NET includes features that let you guide and enhance the XML generation process. There are three main types of guidance you can provide to the XML content: namespace identification, child table nesting, and column management. Identifying Namespaces XML includes a namespace feature that lets you group content by purpose, even among tags that appear within the same parent element. Three ADO.NET classes—DataSet, DataTable, and DataColumn—include properties that let you assign both the namespace and the namespace prefix that will appear in the XML tags associated with the table and column values. Dwonloaded from: iDATA.ws 112 Microsoft ADO.NET 4 Step by Step Each of these three classes includes a Namespace property, a string value containing the tar- get XML namespace name. A second property, Prefix, defines the short prefix prepended to tag names that belong to the namespace. The following code sets the namespace and prefix for a DataTable; the process for setting these values in a DataSet or DataColumn is identical: C# DataTable customers = new DataTable("Customer"); customers.Namespace = "corporate"; customers.Prefix = "co"; Visual Basic Dim customers As New DataTable("Customer") customers.Namespace = "corporate" customers.Prefix = "co" The addition of the namespace and the prefix modifies the generated XML to include the necessary xmlns attributes and prefix components. <co:Customer xmlns:co="corporate"> <ID xmlns="corporate">1</ID> <BusinessName xmlns="corporate">City Power & Light</BusinessName> . Setting only the DataTable (or DataSet) namespace values applies the xmlns tag to each contained column-related element. To change these column entries to prefix-bearing tags instead, set the Namespace and Prefix properties within each of the table’s DataColumn objects. The constructor for the DataTable class also includes a parameter that sets the Namespace property during object creation. Neither DataSet nor DataColumn includes such a parameter. C# DataTable customers = new DataTable("Customer", "corporate"); Visual Basic Dim customers As New DataTable("Customer", "corporate") The namespace and prefix settings are overridable. Setting these values at the DataSet level affects all tables within the data set except those that have their own distinct namespace val- ues. Setting the DataTable-level fields affects its columns unless you override it by setting the two properties in the DataColumn object. Dwonloaded from: iDATA.ws Chapter 7 SavingandRestoringData 113 Nesting Child Tables By default, each table within a DataSet has its rows output at the same element level. In a data set with Customer and Order tables, each row in the Customer table would appear within the data set’s top-level XML element, followed by each row in the Order table at the same level as the Customer records. Sometimes it is better to have the child table records that belong to a parent record physically appear within their parent XML element. Sample code earlier in this chapter showed how adding an extra argument to the DataTable.WriteXml method would accomplish this. But when generating XML for an entire DataSet, you must indicate your desire to nest child tables by setting the Nested property in the relevant DataRelation object. C# DataRelation customerOrder = new DataRelation( customers.Columns["ID"], orders.Columns["CustomerID"]); customerOrder.Nested = true; Visual Basic Dim customerOrder As New DataRelation( customers.Columns!ID, orders.Columns!CustomerID) customerOrder.Nested = True Managing and Positioning Columns As ADO.NET outputs the XML content for a DataTable, it first generates a tag for each row in the table, using the table’s name as the containing tag. Within this row tag, each column gets its own tagged element. The data for each column appears as text within the column element. The following content shows a single row from the “Customer” table, with subordinate tag elements for each of the four columns in the row: <Customer> <ID>1</ID> <BusinessName>City Power & Light</BusinessName> <AnnualFee>500</AnnualFee> <ContractDate>2008-06-01T00:00:00-07:00</ContractDate> </Customer> Sometimes you might want one or more columns to appear as attributes for the row-level tag instead. <Customer ID="1"> Dwonloaded from: iDATA.ws 114 Microsoft ADO.NET 4 Step by Step This is accomplished by setting the DataColumn.ColumnMapping property for the relevant column object. This property can be set to one of four enumerated values: MappingType.Element The column data appears within its own XML tag element. This is the default setting for all columns. MappingType.Attribute The column value is moved into the row’s tag and stored as an XML attribute. MappingType.SimpleContent The data for this column becomes the entire content for the row’s tag element. Only one column within a table can be designated as the SimpleContent column. All other columns must either be set as attributes or must be hidden. Note Setting a column’s mapping type to SimpleContent will generate an exception if any other columns in the same table have a mapping type of Element or SimpleContent. MappingType.Hidden This column is excluded from the generated XML content. In addition to setting the ColumnMapping property, the constructor for the DataColumn ob- ject lets you define the mapping type. C# DataColumn orderID = new DataColumn("ID", typeof(int), MappingType.Attribute); Visual Basic Dim orderID As New DataColumn("ID", GetType(Integer), MappingType.Attribute) Generating XML from a DataSet : C# 1. Open the “Chapter 7 CSharp” project from the installed samples folder. The project in- cludes one Windows.Forms class named Serialization. 2. Open the source code view for the Serialization form. Locate the ActGenerate_Click function. This routine produces the XML content from a sample DataSet containing two tables: Customer and Order. 3. Just after the “Set the XML namespace” comment, add the following statements: SampleDataSet.Tables["Customer"].Namespace = TableNamespace.Text.Trim(); SampleDataSet.Tables["Customer"].Prefix = TablePrefix.Text.Trim(); SampleDataSet.Tables["Order"].Namespace = TableNamespace.Text.Trim(); SampleDataSet.Tables["Order"].Prefix = TablePrefix.Text.Trim(); This code sets the namespace and prefix values for both of the sample tables. Dwonloaded from: iDATA.ws Chapter 7 SavingandRestoringData 115 Note As mentioned in the chapter discussion, you can also define namespace and prefix val- ues within each DataColumn. Although it is not included in the sample code, consider adding code that will loop through all columns in each of the two tables and add the user-specified namespace and prefix values. 4. Just after the “Indicate the relationship type” comment, add the following line: SampleDataSet.Relations[0].Nested = NestChildRecords.Checked; This statement determines whether the order rows for each customer record are con- tained within the <Customer> tag (true) or whether all <Order> tags appear after and at the same level as all the <Customer> tags in the XML (false). 5. Just after the “Build a memory stream to hold the results” comment, add the following code: holdBuffer = new MemoryStream(8192); SampleDataSet.WriteXml(holdBuffer, (XmlWriteMode)OutputWriteMode.SelectedItem); These lines perform the actual XML generation, sending the results to a stream, in this case a MemoryStream instance. The remaining code in the event handler moves the XML content from the stream to an on-form text box. 6. Run the program. Use the fields in the upper-right corner of the form to alter the XML content and then click Generate to produce the XML. As an example, set the XML Write Mode to WriteSchema, change the Mapping for both Parent.ID and Child.ID to Attribute, and set the Mapping for Child.CustomerID to Hidden. Click Generate. The XML will contain the XSD schema for the data set, followed by distinct <Customer> and <Order> elements. Dwonloaded from: iDATA.ws 116 Microsoft ADO.NET 4 Step by Step Generating XML from a DataSet : Visual Basic 1. Open the “Chapter 7 VB” project from the installed samples folder. The project includes one Windows.Forms class named Serialization. 2. Open the source code view for the Serialization form. Locate the ActGenerate_Click function. This routine produces the XML content from a sample DataSet containing two tables: Customer and Order. 3. Just after the “Set the XML namespace” comment, add the following statements: SampleDataSet.Tables("Customer").Namespace = TableNamespace.Text.Trim SampleDataSet.Tables("Customer").Prefix = TablePrefix.Text.Trim SampleDataSet.Tables("Order").Namespace = TableNamespace.Text.Trim SampleDataSet.Tables("Order").Prefix = TablePrefix.Text.Trim This code sets the namespace and prefix values for both of the sample tables. Note As mentioned in the chapter discussion, you can also define namespace and prefix val- ues within each DataColumn. Although it is not included in the sample code, consider adding code that will loop through all columns in each of the two tables and add the user-specified namespace and prefix values. 4. Just after the “Indicate the relationship type” comment, add the following line: SampleDataSet.Relations(0).Nested = NestChildRecords.Checked This statement determines whether the order rows for each customer record are con- tained within the <Customer> tag (True) or whether all <Order> tags appear after and at the same level as all the <Customer> tags in the XML (False). 5. Just after the “Build a memory stream to hold the results” comment, add the following code: holdBuffer = New MemoryStream(8192) SampleDataSet.WriteXml(holdBuffer, CType(OutputWriteMode.SelectedItem, XmlWriteMode)) These lines perform the actual XML generation, sending the results to a stream, in this case a MemoryStream instance. The remaining code in the event handler moves the XML content from the stream to an on-form text box. Dwonloaded from: iDATA.ws [...]... for XML data 118 Microsoft ADO.NET 4 Step by Step Chapter 7 Quick Reference To Do This Export a DataSet to a file as XML Create a DataSet instance Add all relevant DataTable, DataRelation, and content objects Call the WriteXml method of the DataSet, passing it the file name as an argument Import file-based XML into a new DataSet Create a new DataSet instance Call the ReadXml method of the DataSet,... own schema using embedded or external XSD and can build hierarchical XML elements based on the relationships in the original DataSet There are other ways to bring ADO.NET data and XML together in your applications LINQ, a major language feature in both Visual Basic and C#, includes data- querying features for both ADO.NET and XML, features that can work in tandem Chapters 17 through 20 in this book... passing it the file name as an argument Generate hierarchical parent-child data Create a DataSet instance Add the relevant DataTable objects Add a DataRelation instance that links the tables Set the DataRelation.Nested property to True Call DataSet.WriteXml to generate the XML content Store a DataColumn as an XML-based attribute Set the DataColumn.ColumnMapping property to MappingType Attribute ... Chapter 7 Saving andRestoring Data 117 6 Run the program Use the fields in the upper-right corner of the form to alter the XML content and then click Generate to produce the XML As an example, set the XML Write Mode to IgnoreSchema; select the Nest Child Records check box; change the Mapping for Child.ID to Attribute; change the Mapping for Child.CustomerID, Child OrderDate, Child.Subtotal, and Child.TaxRate... change the Mapping for Child.CustomerID, Child OrderDate, Child.Subtotal, and Child.TaxRate to Hidden; and finally change the Mapping for Child.Total to SimpleContent Click Generate The XML will contain a simple set of customer records, each containing one or more tags with an ID attribute, and with the order total set as the element content Summary This chapter introduced the XML-specific features . Reconstructs the DataTable members of the DataSet without loading in the data. Dwonloaded from: iDATA.ws Chapter 7 Saving and Restoring Data 111 XmlReadMode.IgnoreSchema. </CustomerDataSet> Dwonloaded from: iDATA.ws Chapter 7 Saving and Restoring Data 109 By default, WriteXml writes XML for only the data rows in each