Managing Multiple DataSets
As your data layer grows, you may find yourself managing multiple typed DataSet classes that overlap slightly, sharing tables between them. Working with multiple datasets means extending the concept of reusable types across multiple XSD documents.
As an example, I'll show you how to build a data-layer on top of Microsoft's Pubs sample database. The sample project contains two datasets: one called EmployeesDS
, which holds employee data and another called SalesDS
, which holds sales data. Both datasets share the Publishers table. By default each generated dataset would contain a schema defining the Publishers table, meaning that if the table changes, you'll have to change the schema in two different places. Ideally, you need a way to define each type once; no matter how many times your application uses or extends that type. That way, when the shared Publishers table changes, you'll only have to modify your code in one place.
To abstract the shared publishers
type, first create a new schema document called DsBase.xsd
. The schema doesn't have to be a DataSet because you're not using it to create any classes. Notice that the schema element needs relatively few attributes.
It's important to notice that I've removed the targetNamespace
attribute from the schema. This technique is known as "chameleon" namespace design, and allows the DsBase
document to take on the namespace of any document that uses it. Think of it as an abstract class. For another example of a chameleon namespace, take a look at these guidelines
Here's the completed base schema.
<?xml version="1.0" encoding="utf-8" ?>
<xs:element name="pub_id" type="xs:string" />
<xs:element name="pub_name" type="xs:string"
<xs:element name="city" type="xs:string"
<xs:element name="state" type="xs:string"
<xs:element name="country" type="xs:string"
Even though you're not creating a DataSet, note that the XML looks the same as in a DataSet schema.
To use the publishers
type you just created, first import the base schema into your DataSets using the include
<xs:include schemaLocation=".\DSBase.xsd" />
Now, you can use everything from the included schema exactly as if it were defined locally. In the XSD file, replace the locally-defined Publishers table with an element of type publishers
<xs:element name="Publishers" type="publishers" />
shows a completed SalesDS.xsd
which uses the imported publishers
shows a screenshot of the schema in the Visual Studio designer. Notice that you can't edit the publishers
type because it's not defined in this schema.
|Figure 3. Back to the Visual Studio Designer: Notice that you can't edit the publishers type because it's not defined in this schema.|
As I mentioned earlier, this technique can help, but there's still something missing: polymorphism. Using XSD gives you a kind of inheritance, but wouldn't it be nice to write generic codefor example, code that could handle either Student or Teacher types equally well? It's certainly possible, but doing so requires using an Object/Relational (O/R) Mapping tool. Such tools provide developers with a less strict coupling between classes and the relational modelan ideal situation, because data modelers and software architects don't always design under the same constraints. You could write an O/R tool, or buy one. But they're not trivial to write (in fact, they can be fiendishly complex), and they're not cheap to buy from a third-party vendor.
The good news is that Microsoft is working on its own O/R Mapper, known as ObjectSpaces, that's planned for inclusion with Visual Studio 2005 (codenamed Whidbey). This tool promises to include a set of classes similar to ADO.NET except with a looser coupling to the database. Until then, we'll just have to get by using XSD.