Using ObjectSpaces

for RuBoard
graphics/newterm.gif

Also last fall, Microsoft revealed preliminary plans for tighter integration of object orientation with ADO.NET through a technical preview referred to as the Microsoft ObjectSpaces framework. This framework consists of a set of classes and interfaces grouped in a namespace ( Microsoft.ObjectSpaces ) that provides an object-oriented mapping layer to access data and might be shipped with a future release of VS .NET. This framework builds on the classes of ADO.NET and those in the System.Xml namespace to provide access to both XML data sources and relational data sources. Figure 21.1 shows the high-level architecture of the ObjectSpaces framework.

Figure 21.1. The Microsoft ObjectSpaces architecture adapted from the SDK documentation.

graphics/21fig01.gif

Caution

Just as with the discussion of Yukon, the ObjectSpaces framework is highly preliminary and should be used only as an idea of what you might see in a future release of VS .NET.


Note that ObjectSpaces provides three primary ways of abstracting data: through the DataSpace , the XmlObjectSpace , or the SqlObjectSpace classes. All three of these classes are derived from ObjectSpace and all read and write their data to an underlying DataSet that is eventually synchronized with a persistent store, such as an XML file or a database using a .NET Data Provider.

The primary difference between the DataSpace and both the XmlObjectSpace and the SqlObjectSpace is that the DataSpace has no inherent persistent store and can simply be created from any existing DataSet . The other two objects implement the IObjectSpace interface, so they can be used polymorphically so that client code needn't be concerned with whether the data resides in XML or in a relational database. In all three cases, the actual data always resides in a DataSet and is simply mapped into and out of the object dynamically by the ObjectSpace object.

To get a feel for how ObjectSpaces work, the following sections will show a simple example of providing object-oriented access to the ComputeBooks Customers table in SQL Server 2000.

Note

For a longer treatment of ObjectSpaces and how it compares architecturally with Enterprise Java Beans (EJB), see my two-part series on the subject on www.informit.com. Note that the example used here is the same as that discussed in the article.


Creating the Persistent Class

graphics/newterm.gif

The first task in exposing data using ObjectSpaces is to define the interface of the entity or object you wish to expose. In the ObjectSpaces Framework, defining the object is accomplished by creating a single persistent class. The persistent class is actually an abstract class (defined with MustInherit in VB or abstract in C#) that defines the properties, fields, methods , and events used by the client. Listing 21.2 shows the persistent class for the Customer object written in VB.

Listing 21.2 A persistent Customer class. This class is used as the base class to allow the ObjectSpaces framework to represent a customer.
 Namespace ComputeBooks.Data   Public MustInherit Class CustomerOS     Public MustOverride ReadOnly Property Id() As Integer     Public MustOverride Property FName() As String     Public MustOverride Property LName() As String     Public MustOverride Property Address() As String     Public MustOverride Property City() As String     Protected MustOverride Property _stateProv() As String     Public MustOverride Property PostalCode() As String     Public MustOverride Property EmailAddress() As String     <AliasAttribute("_stateProv")> _     Public Property StateProv() As String       Get         Return _stateProv       End Get       Set(ByVal Value As String)         If Len(Trim(Value)) <> 2 Then           Throw New ArgumentException("State must be 2 characters")         Else           _stateProv = Trim(Value)         End If       End Set     End Property     Public ReadOnly Property Name() As String       Get         Return Trim(Me.FName) & " " & Trim(Me.LName)       End Get     End Property     Public Sub OnCreate() 'can accept arguments       ' called at object creation     End Sub     Public Sub OnMaterialize()       ' called the first time an object is retrieved from the data store     End Sub     Public Sub OnDelete()       ' called when the object is deleted from the ObjectSpace     End Sub   End Class End Namespace 
graphics/analysis.gif

At runtime, the ObjectSpaces framework creates a derived class from the persistent class and maps the data from the DataSet into and out of the members of the class. In addition, you'll notice that you can provide your own properties and methods, such as Name in Listing 21.2, that can be calculated from other members or perform other business functions.

Two of the interesting features of the persistent class are that you can insert business logic into the Get and Set blocks of a property, and you can reference remote methods to abstract business logic. The former feature is illustrated in the StateProv property that aliases the abstract _stateProv property by including the AliasAttribute and includes logic to validate the property as it is populated in the Set block. The latter feature is beyond the scope of this book, but entails creating an abstract method in the persistent class and then referencing the remote method in the XML mapping file discussed later.

Another interesting feature of the persistent class is that it supports the OnCreate , OnMaterialize , and OnDelete methods called by the ObjectSpaces framework when the object is created, populated from the data store, and removed, respectively. Although not shown in Listing 21.2, the OnCreate method is particularly useful for passing arguments to the class as it is instantiated and can be used, for example, to assign a client-generated primary key value to the object.

Although not shown in Listing 21.2, the persistent class can also include attributes that identify the primary key field and that link persistent classes in a parent-child relationship. In that way, when the ObjectSpaces framework instantiates an object of type Customer ; for example, the client would be able to traverse the Orders for that customer as well, assuming you created a persistent class for Orders .

Creating the Mapping Files

After the persistent class is complete, you can create an XML mapping file and source file that define how columns in a database map to the properties of the persistent class and the data store connection information for that class, respectively.

Note

As an alternative to simply creating the mapping file by hand, the ObjectSpaces framework will likely ship with a graphical tool that can be accessed by right-clicking on the project in VS .NET and selecting the template item under Add New Item.


Listing 21.3 shows the simple mapping file for the Customer persistent class.

Listing 21.3 XML mapping file. This file is used by the ObjectSpaces framework to map database tables and columns to the persistent class.
 <map xmlns="http://www.microsoft.com/ObjectSpaces-v1">   <type name="Customer" dataSource="Customers" source="ComputeBooks">     <uniqueKey name="Id" mappedBy="autoIncrement" dataSource="CustomerId"/>     <property name="FName" dataSource="FName"/>     <property name="LName" dataSource="LName"/>     <property name="Address" dataSource="Address"/>     <property name="City" dataSource="City"/>     <property name="_stateProv" dataSource="StateProv"/>     <property name="PostalCode" dataSource="PostalCode"/>     <property name="EmailAddress" dataSource="EmailAddress"/>   </type> </map> 
graphics/analysis.gif

You'll notice from Listing 21.3 that the type element is used to reference the persistent class in addition to specifying the name of the table ( dataSource ) and the connection ( source ) to use to get to the table. Each property element maps a property of the persistent class ( name ) to the name of a column in the table ( dataSource ). In addition, here the primary key is identified using the uniqueKey element and mapping it to the CustomerId column in the table. The mappedBy attribute indicates that the column is generated automatically by the data source for use with IDENTITY columns in SQL Server and sequences in Oracle. Because the Id property is generated from the data In addition to creating the mapping file, you also provide a connection file as shown here:

 <sources xmlns="http://www.microsoft.com/ObjectSpaces-v1">   <source name="ComputeBooks" adapter="sql"    connection="Data Source=ssosa; Integrated Security=SSPI; Database=ComputeBooks"/> </sources> 

The connection file simply identifies the connection ( source ) referenced in the mapping file in addition to the .NET Data Provider to use ( sql or oledb ) and the connection string to pass to the database server. By putting the connection information in an XML file, you can abstract it from the client code as well.

Querying the Customer

After the mapping and connection files are in place, the client can write code against the persistent class using the XmlObjectSpace or SqlObjectSpace classes. For example, to query a single customer, you could write the following code:

 Dim os As New SqlObjectSpace("connect.xml", "map.xml") Dim myCustomer As Customer Dim strName As String myCustomer = CType(os.GetObject(GetType(Customer), "Id = 1"), Customer) strName = myCustomer.Name 
graphics/newterm.gif

First, the SqlObjectSpace object is instantiated and passed the connection and mapping files shown previously. SqlObjectSpace is used because the data exists in a relational database. Next, the myCustomer object is populated using the GetObject method of SqlObjectSpace inherited from the IObjectSpace interface. You'll notice that the string "Id = 1" is passed as the second argument. This syntax is referred to as OPath, a derivative of XPath, which Microsoft developed specifically for the ObjectSpaces framework. Behind the scenes, the ObjectSpaces framework uses the combination of the OPath query and the mapping and connect files to connect to the database and formulate a SELECT statement to retrieve the customer identified with the CustomerID of 1. The result is then mapped into the myCustomer object, where the properties such as Name are then available.

In addition, through the GetObjects method of the IObjectSpace interface, you can automatically query multiple objects like so:

 For Each myCustomer In os.GetObjects(GetType(Customer), "City = 'Richmond'")   Console.WriteLine(vbCrLf & "Customer Id: " & myCustomer.Id & _       vbCrLf & "Name: " & myCustomer.Name & _       vbCrLf & "City: " & myCustomer.City & _       vbCrLf & "PostalCode: " & myCustomer.PostalCode & vbCrLf) Next 

Once again, the framework formulates the correct SELECT statement based on the OPath query and configuration files.

Because both the XmlObjectSpace and SqlObjectSpace classes inherit the IObjectSpace interface, you can also program against either one polymorphically by simply referencing a variable of type IObjectSpace and using the CreateObjectSpace method of the ObjectSpaceFactory class like so:

 Dim os As IObjectSpace = ObjectSpaceFactory.CreateObjectSpace("customer.xml") 

In this case, customer.xml is a file that specifies the ObjectSpace object to use and the arguments to pass to its constructor as shown in the following code snippet. Here the type attribute points to the SqlObjectSpace object that will be used, whereas the arg elements point to the mapping files discussed previously.

 <objectspace type="Microsoft.ObjectSpaces.SqlObjectSpace"   xmlns="http://www.microsoft.com/ObjectSpaces-v1">     <arg>connect.xml</arg>     <arg>map.xml</arg> </objectspace> 

Updating the Customer

Of course, you can also create new rows in a database using ObjectSpaces. This is done using the CreateObject method of the IObjectSpace interface. The code in Listing 21.4 creates a new customer and populates its properties before calling the Update method to persist the object in the data store.

Listing 21.4 Creating a new customer. This listing creates a new customer using the CreateObject method and saves it using the UpdateAll method.
 myCustomer = CType(os.CreateObject(GetType(Customer)), Customer) With myCustomer     .FName = "Beth"     .LName = "Fox"     .Address = "21508 W44th"     .City = "Overland Park"     .StateProv = "MO"     .PostalCode = "33221"     .EmailAddress = "bethafox@foxden.com" End With Try   ' Save Changes   os.Update(myCustomer) Catch ex As UpdateException   ' Handle error End Try Console.WriteLine("New ID = " & myCustomer.Id) 
graphics/analysis.gif

You'll notice from Listing 21.4 that the Update method is passed the new customer. The framework then proceeds to generate an INSERT or UPDATE SQL statement as appropriate and execute it on the data source. If the update succeeds, the framework automatically populates the new Id generated from the database.

If multiple customers are modified or added, the UpdateAll method can be used instead and can accept different arguments specified in the UpdateBehavior enumeration. For example, specifying the ThrowAtFirstError value will throw an exception as soon as the first error is returned from the data source. The IObjectSpace interface also supports Resync and ResyncAll methods that can be used to synchronize one or more objects from the data store to the client.

Note

Although persistence managed by the ObjectSpaces Framework doesn't directly support stored procedures in the technical preview version, look for it to do so at least with the SQL Server .NET Data Provider in future releases.


The example shown today allows the ObjectSpaces Framework to handle the persistence to the data source automatically. However, when the data is more complex or comes from heterogeneous sources, you can opt to perform the persistence yourself.

This is accomplished by creating a class derived from the ObjectCustomizer abstract class and implementing methods such as CreateRow , GetRow , GetRows , InsertRows , UpdateRows , DeleteRows , GetChildRows , and GetParentRow . The class is then referenced in the type element of the mapping file so that the framework can instantiate it and call its methods when appropriate.

for RuBoard


Sams Teach Yourself Ado. Net in 21 Days
Sams Teach Yourself ADO.NET in 21 Days
ISBN: 0672323869
EAN: 2147483647
Year: 2002
Pages: 158
Authors: Dan Fox

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net