Download



The XmlAdapter Class and XML Views

The XmlAdapter class provides query and update capabilities via an XML view to a SQL Server database. If you are a SQLXML advocate, you may be familiar with updategrams, which provide a declarative format for pushing changes to SQL Server. The XmlAdapter provides a programmatic way to achieve this in code, and it notably works with any XML document that is mapped.

The XmlAdapter Class

The XmlAdapter class provides the ability to synchronize changes made to an XPathDocument2 instance with SQL Server. Figure through 7.4 contain a concise reference to the constructors, properties, methods, and event of this class. Then we'll look at some of the associated classes before examining how we can use the XmlAdapter in code examples.

The XmlUpdateEventArgs Class

The XmlUpdateEventArgs class provides information about failures for updates to SQL Server, the items that were affected, and the underlying error that occurred during the update. Figure documents the properties of this class.

The Constructors for the XmlAdapter Class

Constructor

Description

XmlAdapter()

Creates an XmlAdapter used to retrieve and update data from an XPathDocument2 to a SQL Server database via an XML view.

XmlAdapter(datasource)

Creates an XmlAdapter used to retrieve and update data from an XPathDocument2 to a SQL Server database via an XML view. The datasource parameter is an XmlResolver, typically an XmlDataSourceResolver, which stores the database connections used by the Fill and Update methods to synchronize the changes.

The Properties of the XmlAdapter Class

Property

Description

AcceptChangesDuringUpdate

A Boolean value that indicates whether AcceptChanges will be called on the XPathDocument2 when the changes have been applied to the SQL Server database using the Update method. The default is True.

ContinueUpdateOnError

A Boolean value that determines whether updates will continue after an error has occurred during the Update process until all have been attempted. Any errors that occur are reported after the Update process has completed. To stop updating after the first error, set this property to False. To continue attempting to update the remaining items, set this property to True. The default is False.

DataSources

A value that provides resolution to data sources used by the Fill and Update methods. An XmlResolver instance can be passed into the constructor or set using this property. Typically this is an XmlDataSourceResolver with DbConnections set to specify the SQL Server database.

The Methods of the XmlAdapter Class

Method

Description

Fill(doc, query)

Executes the XmlCommand query and fills the XPathDocument2 doc with the results of the query. Any errors that occur during the Fill cause the XPathDocument2 to revert to its original state before Fill was called.

Fill(doc, query, arglist)

As above, except the XmlQueryArgumentList provides the ability to pass parameter values to the query before the Fill method is called.

Update(changes, MappingSchema)

Pushes the changes back into the database. The changes parameter is an enumerator of XPathChangeNavigators that point to the changed nodes, and the MappingSchema defines the XML view mapping with which to apply the updates.

Update(doc, MappingSchema)

As above, except that the doc parameter is the XPathDocument2 from which an XPathChange Navigator is retrieved.

Update(navigator, MappingSchema)

As above, but with a single XPathChange Navigator as the first parameter.

The Event of the XmlAdapter Class

Event

Description

OnUpdateError

An UpdateEventHandler that is called when an update fails. The event handler is called once for each row that fails to update. The number of rows updated depends on the mapping in the XML view. The XmlUpdateEventArgs class contains the names of the items that failed during the update and the appropriate error information.

The Properties of the XmlUpdateEventArgs Class

Property

Description

ErrorItems

An enumerator for the XPathChangeNavigators, each pointing to an item that was not successfully updated to the SQL Server. The number of items in the array depends on the unit of change. For example, if a Customer node is created in the XPathDocument2 and the insert fails, the ErrorItems property contains an array of XPathChangeNavigators pointing to the items in the XPathDocument2 that map to the Customer row in SQL Server.

Executed

A Boolean value that indicates whether or not the update was attempted. This allows you to distinguish errors that occur because of a problem during the update from errors that occur because the update was never attempted.

InnerException

The underlying exception received from SQL Server.

The XmlDataSourceResolver Class

The XmlDataSourceResolver class provides the information about database connections and XML documents over which queries are performed. The XmlAdapter and XQueryProcessor classes use this to provide a set of named values at query execution time and to determine the data sources. The constructors, properties, and methods of this class are detailed in Figure, 7.7, and 7.8, respectively.

The Constructors for the XmlDataSourceResolver Class

Constructor

Description

XmlDataSourceResolver()

Creates an XmlDataSourceResolver that resolves data sources, either to databases through DbConnection instances or to XML documents through an XPathNavigator2. The XmlDataSourceResolver is an XmlResolver that supports enumeration.

XmlDataSourceResolver (nametable)

As above, with the nametable parameter specifying a name table that is shared across the data sources.

The Properties of the XmlDataSourceResolver Class

Property

Description

NameTable

Returns the XmlNameTable for the XmlDataSourceResolver, which is shared across all the XML documents added to the XmlDataSourceResolver.

Count

Returns the number of data sources for the XmlDataSourceResolver.

Item

Returns the value associated with the given key.

Credentials

Allows the user to provide credentials that are used in Web requests for authentication purposes.

The Methods of the XmlDataSourceResolver Class

Method

Description

Add()

Allows various XML or database connections to be added to the XmlDataSourceResolver, with a specified name. The XML documents can be XPathNavigator2 or XmlReader instances, or XML from a disk file or URL. The database connections are either IDbConnection or IDbTransaction interfaces. The overloads of this method are:

  • Add(name, DbConnection)

  • Add(name, DbTransaction)

  • Add(name, XPathNavigator2)

  • Add(name, XmlReader)

  • Add(name, source-url)

Clear

Removes all the connections from the XmlDataSourceResolver.

Contains(item-uri)

Returns a Boolean value indicating whether an item associated with the specified URI exists in the XmlDataSourceResolver.

Remove(item-uri)

Removes the item with the specified URI from the XmlDataSourceResolver.

GetEntity(absolute-uri, role, object-to-return)

Returns either XPathNavigator2 or IDbConnection instances, depending on the specified object-to-return for the given absolute-uri. The role parameter is provided for future extensibility.

ResolveUri(base-uri, relative-uri)

Generates an absolute URI from a base URI and a relative URI for use with the GetEntity method.

XML Views Using XSD, RSD, and MSD Schemas (Three-Part Mapping)

To use the XmlAdapter, you need to understand how XML views are created for querying and updating SQL Server. In Chapter 5 we discussed how XML views are a declarative XML provider for translating from the relational domain to the XML domain, by mapping elements and attributes to tables and columns.

Let's look at what it takes to write an XML view using the declarative mapping format. The mapping translates structure and relationships between data models, and in order to achieve this we use a persistent representation of each. To see it in more detail, we'll examine the mapping for just a small section of the Northwind sample database found in SQL Server 2000. We'll map the Customers, Orders, and related Products tables.

Recall that the three-part mapping requires three documents:

  1. A W3C XML schema for the XML domain (XSD)

  2. A Relational Schema Definition (RSD) for the relational domain

  3. A Mapping Schema Definition (MSD) for the mapping transformation between the domains

The XSD View for the Northwind Database

The XSD document (itself an XML schema) defines the shape of the XML view that is exposed and that is available to query against. In this example we create a structure that is a list of customers, their orders, and the products for each order. We have also decided to represent additional information as attributes, such as the customer name. The XSD view is shown in Listing 7.1.

The XSD Mapping Document
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <xsd:element name="Customers">
 <xsd:complexType>
 <xsd:sequence>
 <xsd:element name="Customer">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element name="Order">
     <xsd:complexType>
      <xsd:sequence>
       <xsd:element name="Product">
        <xsd:complexType>
         <xsd:attribute name="UnitQuantity" type="xsd:integer"/>
         <xsd:attribute name="ProductName" type="xsd:string"/>
         <xsd:attribute name="UnitPrice"  type="xsd:string" />
         <xsd:attribute name="QuantityPerUnit" type="xsd:string"/>
        </xsd:complexType>
       </xsd:element>
      </xsd:sequence>
      <xsd:attribute name="CustomerID" type="xsd:string" />
      <xsd:attribute name="orderid" type="xsd:string"/>
      <xsd:attribute name="OrderDate" type="xsd:string"/>
      <xsd:attribute name="ShipCity" type="xsd:string"/>
     </xsd:complexType>
    </xsd:element>
   </xsd:sequence>
   <xsd:attribute name="name" type="xsd:string" />
   <xsd:attribute name="CustomerID" type="xsd:string" />
   <xsd:attribute name="Country" type="xsd:string" />
   <xsd:attribute name="City" type="xsd:string" />
  </xsd:complexType>
 </xsd:element>
 </xsd:sequence>
 </xsd:complexType>
 </xsd:element>
</xsd:schema>
The RSD View for the Northwind Database

The RSD document specifies the shape of the relational view that represents the section of the database to which we want to map the XML view. The RSD is a serialized representation of the Northwind database tables, and Listing 7.2 shows the Customers, Orders, Order Details, and Products tables and the named columns for each table.

The RSD Mapping Document
<rsd:Database Owner="sa" Name="Northwind"
     xmlns:rsd="http://schemas.microsoft.com/data/2002/09/28/rsd">
 <rsd:Schema Name="dbo">
 <rsd:Tables>
  <rsd:Table Name="Orders">
   <rsd:Columns>
    <rsd:Column Name="OrderID" AutoIncrement="1" IncrementStep="1"
                SqlType="int" IncrementSeed="1" />
    <rsd:Column Name="CustomerID" SqlType="nchar" AllowDbNull="1"
                Length="5" />
    <rsd:Column Name="EmployeeID" SqlType="int" AllowDbNull="1" />
    <rsd:Column Name="OrderDate" SqlType="datetime" AllowDbNull="1" />
    <rsd:Column Name="RequiredDate" SqlType="datetime"
                AllowDbNull="1"/>
    <rsd:Column Name="ShippedDate" SqlType="datetime"
                AllowDbNull="1"/>
    <rsd:Column Name="ShipVia" SqlType="int" AllowDbNull="1" />
    <rsd:Column Name="Freight" SqlType="money" AllowDbNull="1" />
    <rsd:Column Name="ShipName" SqlType="nvarchar" AllowDbNull="1"
                Length="40" />
    <rsd:Column Name="ShipAddress" SqlType="nvarchar" AllowDbNull="1"
                Length="60" />
    <rsd:Column Name="ShipCity" SqlType="nvarchar" AllowDbNull="1"
                Length="15" />
    <rsd:Column Name="ShipRegion" SqlType="nvarchar" AllowDbNull="1"
                Length="15" />
    <rsd:Column Name="ShipPostalCode" SqlType="nvarchar"
                AllowDbNull="1" Length="10" />
    <rsd:Column Name="ShipCountry" SqlType="nvarchar" AllowDbNull="1"
                Length="15" />
   </rsd:Columns>
    <rsd:Constraints>
     <rsd:PrimaryKey Name="PK_Orders">
      <rsd:ColumnRef Name="OrderID" />
     </rsd:PrimaryKey>
     <rsd:ForeignKey Name="FK_Orders_Customers"
                     ForeignTable="Customers"
                     UpdateRule="None" DeleteRule="None">
      <rsd:ColumnMatch Name="CustomerID" ForeignName="CustomerID" />
     </rsd:ForeignKey>
    </rsd:Constraints>
   </rsd:Table>
   <rsd:Table Name="Products">
    <rsd:Columns>
     <rsd:Column Name="ProductID" AutoIncrement="1" IncrementStep="1"
                 SqlType="int" IncrementSeed="1" />
     <rsd:Column Name="ProductName" SqlType="nvarchar" Length="40" />
     <rsd:Column Name="SupplierID" SqlType="int" AllowDbNull="1" />
     <rsd:Column Name="CategoryID" SqlType="int" AllowDbNull="1" />
     <rsd:Column Name="QuantityPerUnit" SqlType="nvarchar"
                 AllowDbNull="1" Length="20" />
     <rsd:Column Name="UnitPrice" SqlType="money" AllowDbNull="1" />
     <rsd:Column Name="UnitsInStock" SqlType="smallint"
                 AllowDbNull="1"/>
     <rsd:Column Name="UnitsOnOrder" SqlType="smallint"
                 AllowDbNull="1"/>
     <rsd:Column Name="ReorderLevel" SqlType="smallint"
                 AllowDbNull="1"/>
     <rsd:Column Name="Discontinued" SqlType="bit" />
    </rsd:Columns>
    <rsd:Constraints>
     <rsd:PrimaryKey Name="PK_Products">
      <rsd:ColumnRef Name="ProductID" />
     </rsd:PrimaryKey>
    </rsd:Constraints>
   </rsd:Table>
   <rsd:Table Name="Order Details">
    <rsd:Columns>
     <rsd:Column Name="OrderID" SqlType="int" />
     <rsd:Column Name="ProductID" SqlType="int" />
     <rsd:Column Name="UnitPrice" SqlType="money" />
     <rsd:Column Name="Quantity" SqlType="smallint" />
     <rsd:Column Name="Discount" SqlType="real" />
    </rsd:Columns>
    <rsd:Constraints>
     <rsd:PrimaryKey Name="PK_Order_Details">
      <rsd:ColumnRef Name="OrderID" />
      <rsd:ColumnRef Name="ProductID" />
     </rsd:PrimaryKey>
     <rsd:ForeignKey Name="FK_Order_Details_Orders"
          ForeignTable="Orders" UpdateRule="None" DeleteRule="None">
      <rsd:ColumnMatch Name="OrderID" ForeignName="OrderID" />
     </rsd:ForeignKey>
     <rsd:ForeignKey Name="FK_Order_Details_Products"
          ForeignTable="Products" UpdateRule="None" DeleteRule="None">
      <rsd:ColumnMatch Name="ProductID" ForeignName="ProductID" />
     </rsd:ForeignKey>
    </rsd:Constraints>
   </rsd:Table>
   <rsd:Table Name="Customers">
    <rsd:Columns>
     <rsd:Column Name="CustomerID" SqlType="nchar" Length="5" />
     <rsd:Column Name="CompanyName" SqlType="nvarchar" Length="40" />
     <rsd:Column Name="ContactName" SqlType="nvarchar" AllowDbNull="1"
                 Length="30" />
     <rsd:Column Name="ContactTitle" SqlType="nvarchar"
                 AllowDbNull="1"
                 Length="30" />
     <rsd:Column Name="Address" SqlType="nvarchar" AllowDbNull="1"
                 Length="60" />
     <rsd:Column Name="City" SqlType="nvarchar" AllowDbNull="1"
                 Length="15" />
     <rsd:Column Name="Region" SqlType="nvarchar" AllowDbNull="1"
                 Length="15" />
     <rsd:Column Name="PostalCode" SqlType="nvarchar" AllowDbNull="1"
                 Length="10" />
     <rsd:Column Name="Country" SqlType="nvarchar" AllowDbNull="1"
                 Length="15" />
     <rsd:Column Name="Phone" SqlType="nvarchar" AllowDbNull="1"
                 Length="24" />
     <rsd:Column Name="Fax" SqlType="nvarchar" AllowDbNull="1"
                 Length="24" />
    </rsd:Columns>
    <rsd:Constraints>
     <rsd:PrimaryKey Name="PK_Customers">
      <rsd:ColumnRef Name="CustomerID" />
     </rsd:PrimaryKey>
    </rsd:Constraints>
   </rsd:Table>
  </rsd:Tables>
 </rsd:Schema>
</rsd:Database>

There is a tool (with source code) available, called RSG (rsg.exe), which allows you to automatically generate RSD file formats from a SQL Server database. This tool is provided along with the sample XSD, RSD, and MSD mapping files you see in this chapter. RSG generates the RSD schema for all the user tables in a given database. The Northwind RSD in Listing 7.2 was generated with the following command:


C:\RSG>rsg.exe "Server=MyServer; database= Northwind; Integrated
graphics/ccc.gif Security=SSPI" C:\RSG

Alternatively you can use an account and password to SQL Server:


C:\RSG>rsg.exe "Server=MyServer; database=Northwind;
graphics/ccc.gif uid=myusername; pwd=mypassword" C:\RSG

The first parameter provides database and connection information. The second parameter provides the file path to the source file for the RSG tool. The resulting RSD file is generated in the current directory.

The MSD Mapping Transformation Document

The MSD file ties together the XSD and the RSD views by mapping structure and relationships between the XML and relational domains. The MSD mapping for our example is shown in Listing 7.3.

The MSD Mapping Document
<m:MappingSchema
  xmlns:m="http://schemas.microsoft.com/data/2002/09/28/mapping">
 <m:DataSources>
  <m:DataSource Name="XML" Direction="Target" Type="Xml">
   <m:Schema Location="nwind.xsd" />
  </m:DataSource>
  <m:DataSource Name="Northwind" Direction="Source" Type="SQL Server">
   <m:Schema Location="nwind.rsd" />
   <m:Variable Name="Orders" Select="Orders" />
   <m:Variable Name="Customers" Select="Customers"/>
   <m:Variable Name="Products" Select="Products"/>
   <m:Variable Name="OrderDetails" Select="Order Details"/>
   <m:Relationship Name="rel1" FromVariable="Customers"
                   ToVariable="Orders">
    <m:FieldJoin From="CustomerID" To="CustomerID" />
   </m:Relationship>
   <m:Relationship Name="rel2" FromVariable="Orders"
                   ToVariable="OrderDetails">
    <m:FieldJoin From="OrderID" To="OrderID" />
   </m:Relationship>
   <m:Relationship Name="rel3" FromVariable="OrderDetails"
                   ToVariable="Products">
    <m:FieldJoin From="ProductID" To="ProductID" />
   </m:Relationship>
  </m:DataSource>
 </m:DataSources>
 
 <m:Mappings>
  <m:Map SourceVariable="Customers"
         TargetSelect="/Customers/Customer">
   <m:FieldMap SourceField="CompanyName" TargetField="@name" />
   <m:FieldMap SourceField="CustomerID" TargetField="@CustomerID" />
   <m:FieldMap SourceField="Country" TargetField="@Country" />
   <m:FieldMap SourceField="City" TargetField="@City" />
  </m:Map
  <m:Map SourceVariable="Orders"
         TargetSelect="/Customers/Customer/Order">
   <m:FieldMap SourceField="orderid" TargetField="@orderid" />
   <m:FieldMap SourceField="CustomerID" TargetField="@CustomerID" />
   <m:FieldMap SourceField="OrderDate" TargetField="@OrderDate" />
   <m:FieldMap SourceField="ShipCity" TargetField="@ShipCity" />
  </m:Map>
 </m:Mappings>
</m:MappingSchema>

Breaking Down the MSD Mapping

To help you understand the nature of these mapping documents, we'll break down the two top-level element definitions in the MSD (the DataSources element and Mappings element) and examine their child elements.

The DataSources Element

The <DataSources> element contains data source references and declarations, as described below.

  • The <DataSource> elements describe data sources. For example, the Northwind mapping schema defines two data sources, nwind.rsd and nwind.xsd. The nwind.rsd is the database source, and the nwind.xsd is the target specified by the Direction attribute:

    <m:DataSource Name="XML" Direction="Target" Type="Xml">
    <m:DataSource Name="Northwind" Direction="Source" Type="SQL Server">
    
  • The <Schema> element provides the schema filename location as a URL:

    <m:Schema Location="nwind.xsd"/>
    <m:Schema Location="nwind.rsd"/>
    
  • The <Variable> element defines a variable that maps to a relational table. For example, the variable named Orders maps to the Orders table and acts as an alias to the table. This alias name is then used in the mappings in the <Mappings> element and can be considered to be a variable or a cursor over the table. You can map a variable to multiple targets, in which case these are populated with the same set of data. In the Northwind mapping schema, the Orders, Customers, Products, and OrderDetails variable names are like cursors on the Orders, Customers, Products, and Order Details tables, respectively:

    <m:Variable Name="Orders" Select="Orders" />
    <m:Variable Name="Customers" Select="Customers"/>
    <m:Variable Name="Products" Select="Products"/>
    <m:Variable Name="OrderDetails" Select="Order Details"/>
    
  • The <Relationship> element defines relationships between variables. In describing the data source, you should declare the variables first and then define the relationships between these variables (or tables) using the <Relationship> element. You describe the parent/ child relationship between the tables using the <FieldJoin> child element of the <Relationship> element and specify the column names as values in the From and To attributes. Alternatively, you can use the Constraint attribute as shown in the last example in this list (on the next page). In the Northwind mapping schema there are three relationships, defined rel1, rel2, and rel3. The relationship rel1 defines a parent/child relationship between the Customers and Orders tables based on the CustomerID column from each one:

    <m:Relationship Name="rel1" FromVariable="Customers"
                    ToVariable="Orders">
     <m:FieldJoin From="CustomerID" To="CustomerID" />
    </m:Relationship>
    
  • Similarly, rel2 defines a parent/child relationship between the Orders and Order Details tables based on the OrderID column:

    <m:Relationship Name="rel2" FromVariable="Orders"
                    ToVariable="OrderDetails">
     <m:FieldJoin From="OrderID" To="OrderID" />
    </m:Relationship>
    
  • Finally, rel3 defines a parent/child relationship between the Products and Order Details tables based on the ProductID column:

    <m:Relationship Name="rel3" FromVariable="Products"
                    ToVariable="Order Details">
     <m:FieldJoin From="ProductID" To="ProductID" />
    </m:Relationship>
    
  • If there is a PrimaryKey or ForeignKey (PK/FK) constraint defined on the relational tables in the RSD, you can specify a Constraint attribute instead. In the Northwind mapping schema we could define another relationship, rel4, between the Customers and Orders tables as shown below. This is equivalent to the relationship rel1 shown earlier:

    <m:Relationship Name="rel4"
                    FromVariable="Customers"
                    ToVariable="Orders"
                    Constraint="FK_Orders_Customers" >
    </m:Relationship>
    
The Mappings Element

The <Mappings> element maps between the XSD and RSD schemas and is a container for the Map elements. It contains the following element definitions.

  • The <Map> child elements are used to specify the mappings between tables (or variables) and elements. If we consider just the Customer element from our Northwind XSD view (Listing 7.1), it has four attributes:

    <xsd:element name="Customer">
     <xsd:complexType>
      <xsd:attribute name="name" type="xsd:string" />
      <xsd:attribute name="CustomerID" type="xsd:string" />
      <xsd:attribute name="Country" type="xsd:string" />
      <xsd:attribute name="City" type="xsd:string" />
     </xsd:complexType>
    </xsd:element>
    
  • The first <Map> element maps the <Customer> element to the Customers table (variable) and the attributes of the <Customer> element to the columns in the Customers table:

    <m:Map SourceVariable="Customers"
           TargetSelect="/Customers/Customer">
     <m:FieldMap SourceField="CompanyName" TargetField="@name" />
     <m:FieldMap SourceField="CustomerID" TargetField="@CustomerID" />
     <m:FieldMap SourceField="Country" TargetField="@Country" />
     <m:FieldMap SourceField="City" TargetField="@City" />
    </m:Map>
    
  • Likewise, the next <Map> element maps the <Orders> element, which is a child of the <Customer> element, to the Orders table (variable) and the attributes of the <Orders> element to the columns in the Orders table:

    <m:Map SourceVariable="Orders"
           TargetSelect="/Customers/Customer/Order">
     <m:FieldMap SourceField="orderid" TargetField="@orderid" />
     <m:FieldMap SourceField="CustomerID" TargetField="@CustomerID" />
     <m:FieldMap SourceField="OrderDate" TargetField="@OrderDate" />
     <m:FieldMap SourceField="ShipCity" TargetField="@ShipCity" />
    </m:Map>
    
  • The SourceVariable and TargetSelect attributes map the variables defined for the Northwind data source to the elements in the Northwind XSD.

  • The <FieldMap> child elements map relational columns to XML schema attributes using the SourceField and TargetField attributes. For example, the CompanyName column in the Customers table is mapped to the name attribute of the <Customer> element.

  • We can also map columns to elements rather than attributes. To do this we need to alter the XSD and the MSD. The XSD schema below shows the <Customer> element with child elements instead of attributes:

    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="Customer">
     <xsd:complexType>
      <xsd:sequence>
       <xsd:element name="name" type="xsd:string" />
       <xsd:element name="CustomerID" type="xsd:string" />
       <xsd:element name="Country" type="xsd:string" />
       <xsd:element name="City" type="xsd:string" />
      </xsd:sequence>
     </xsd:complexType>
    </xsd:element>
    </xsd:schema>
    

In order to map this element-centric XSD, the MSD mapping would need to be amended as shown in Listing 7.4.

The Amended MSD for Element-Centric Mapping
<m:Mappings>
 <m:Map SourceVariable="Customers"
        TargetSelect="/Customers/Customer"/>
 <m:Map SourceVariable="Customers"
        TargetSelect="/Customers/Customer/name">
  <m:FieldMap SourceField="name" TargetField="text()"/>
 </m:Map>
 <m:Map SourceVariable="Customers"
        TargetSelect="/Customers/Customer/CustomerID">
  <m:FieldMap SourceField="CustomerID" TargetField="text()"/>
 </m:Map>
 <m:Map SourceVariable="Customers"
        TargetSelect="/Customers/Customer/Country">
  <m:FieldMap SourceField="Country" TargetField="text()"/>
 </m:Map>
 <m:Map SourceVariable="Customers"
        TargetSelect="/Customers/Customer/City">
  <m:FieldMap SourceField="City" TargetField="text()"/>
 </m:Map>
</m:Mappings>

Note that the RSD does not have to change, only the structure of the XML view and how it is mapped.

The XmlViewSchema and XmlViewSchemaDictionary Classes

Now that we have shown the mapping format and syntax, there are two classes we should introduce that represent the XML view: the XmlView Schema and the XmlViewSchemaDictionary. Both of these can be found in the System.Xml.Query namespace of the Framework.

The XmlViewSchema class represents a compiled XML view. The mapping allows a non-XML source, such as a relational database, to represent its data in a shape that conforms to an XML schema or XSD. In mapping terminology, the exposed XSD is the "target" or "query" side of the mapping while the underlying data source is the "source" or "persistent" side of the mapping.

The XmlViewSchemaDictionary is a dictionary of XmlViewSchema objects, where the five overloads of the Add method (see Figure earlier) provide the ability to add new XML views. The views can be used to issue queries and updates to the data source such as SQL Server. You pass in an MSD file reference, and the Add method creates a new XmlViewSchema object, compiles the mapping, and adds this to the dictionary.

The System.Data.Mapping Namespace

The System.Data.Mapping namespace contains object models for the MSD and RSD formats. The one class that is most important here for using an XmlAdapter is the MappingSchema, which represents the compiled state for the MSD file. This is used when we call the Update method on the XmlAdapter.

Meanwhile, the XSD object model classes are in the System.Xml.Schema namespace and were shipped in version 1.x of the .NET Framework. Many classes in this namespace are beyond the scope of this book and for the most part are never needed by applications using XML views—only by tools that manipulate the object models.