Chapter 9: Working with Strongly Typed Objects

When to Use Strongly Typed DataSet Objects

Every developer I've spoken with, both inside and outside of Microsoft, has been impressed by how strongly typed DataSet objects simplify the development process. However, many developers still have reservations about using strongly typed DataSet objects in their applications.

Most of these developers have not looked at the code that the XML Schema Definition Tool generates, nor have they compared the performance of untyped and strongly typed DataSet objects. And you know what? I was one of those skeptical developers until I started doing research for this chapter. (What did I find? I'll get to that shortly.)

Software Components and Swiss Army Knives

A decade or two ago, I was a Boy Scout. There's an unwritten rule that every Boy Scout must own a Swiss Army knife. Swiss Army knives came in handy on our camping trips. Most of the food we ate came out of cans, so the can opener blade got a lot of use. And you'd always find Scouts whittling wood around the campfire.

Some Swiss Army knives have more gadgets than others. Thankfully, at least one Scout always had a knife that came with a pair of tweezers, because when you combine young boys and wood, you're bound to get splinters. At one point, I owned a Swiss Army knife that had 20-some gadgets. It had everything but a squeegee to wash a car's windshield. I probably used two or three gadgets regularly, but the rest got little use because I had no need for them or they didn't work well.

Another unwritten rule says that children will lose small items and that the chances of the child losing an item are proportional to the cost of the item. At the end of any camping trip, at least one Scout would have lost a knife. When I lost my super-sized knife, I bought a nice but much more basic model. In fact, I still have it. I don't use it often, but all of the gadgets have come in handy at one time or another. The bottle opener and corkscrew get more use now than when I was 12 years old.

Why didn't I buy another knife with a plethora of gadgets? Simple. The larger one was more expensive and heavier. I didn't buy the very simplest knife, however, because I did occasionally need a couple gadgets. So, I bought a mid-size knife with just the gadgets I thought I would find useful.

The same premise holds true with software components. Simpler components are generally faster than the ones that offer a long list of features.

Strongly typed DataSet objects definitely expose more functionality than untyped DataSet objects do. However, as with Swiss Army knives, you won't always need the advanced features. If you're not going to use the additional gadgets, you're better off sticking with a more basic model.

Design-Time Benefits

I've already covered the most obvious design-time benefit of strongly typed DataSet objects: writing code to access data in a strongly typed DataSet is much easier than with a standard untyped DataSet, thanks to statement completion and IntelliSense in Visual Studio .NET.

There's also less code to write because the strongly typed DataSet class contains code to build the schema and to create the necessary DataTable, DataColumn, DataRelation, and Constraint objects in the class's initialization code. If you're using an untyped DataSet, you have three options for adding schema information to your DataSet: writing the code yourself, loading the schema from an .xsd file using the DataSet object's ReadXmlSchema method, or using the DataAdapter object's FillSchema method. Of these three options, using FillSchema requires the least amount of work at design time (because ReadXmlSchema requires that you build your .xsd file). However, in Chapter 5 we discussed why you should avoid using this feature in your code whenever possible.

If you're building a Windows or Web application that uses data binding, it will be much easier to bind your controls at design time if you're using a strongly typed DataSet. Why? Because the strongly typed DataSet contains its own schema information, Visual Studio .NET can provide you with a list of tables and columns to which you can bind your control.

Figure 9-4 shows an example. We can specify that we want to view just the orders for the current customer by selecting the DataRelation called CustomersOrders. Notice that the grid displays the structure of the Orders DataTable. No code was written (or harmed) in the building of this sample.

Figure 9-4

Data binding using a strongly typed DataSet

Developers who build multi-tiered applications can gain design-time benefits by using strongly typed DataSet objects. When you add a reference to a class library or a Web service that returns a strongly typed DataSet, your project will have its own copy of the .xsd file and the class file for the strongly typed DataSet. Thus, the client application can still take advantage of the design-time benefits of strongly typed DataSet objects.

Run-Time Benefits

What are the run-time implications of using strongly typed DataSet objects? How do they affect the performance of your applications? Not only is it easier to write code to access the contents of a strongly typed DataSet, but that code can also improve the performance of your application. The following code snippet shows the standard way to assign the contents of a column to a text box, using both an untyped and a strongly typed DataSet:

Visual Basic .NET

'Untyped Dim dsUntyped As New DataSet() 'Create and fill the DataSet.  txtCompanyName.Text =    dsUntyped.Tables("Customers").Rows(0)("CompanyName") 'Strongly typed Dim dsTyped As New Chapter9() 'Fill the DataSet.  txtCompanyName.Text = dsTyped.Customers(0).CompanyName

Visual C# .NET

//Untyped DataSet dsUntyped = new DataSet(); //Create and fill the DataSet.  txtCompanyName.Text =    (string) dsUntyped.Tables["Customers"].Rows[0]["CompanyName"]; //Strongly typed Chapter9 dsTyped = new Chapter9(); //Fill the DataSet.  txtCompanyName.Text = dsTyped.Customers[0].CompanyName;

The strongly typed code yields better performance. How much better? Well, as of this writing, Visual Studio .NET is still in beta, and it's always tricky to gauge the performance of beta products. However, the tests I've run have shown that the strongly typed code runs nearly twice as fast as the untyped code in the preceding code snippet.

How does the strongly typed DataSet provide improved performance? In Chapter 6, you learned that the DataRow object allows you to access the contents of a column by supplying the name of the column, the ordinal for the column, or the DataColumn object itself. Code that uses the actual DataColumn object yields the best performance, but it's the most difficult to write and maintain. Supplying the column name as a string results in code that's easy to write and maintain, but it also results in the worst performance.

The code generated by the XML Schema Definition Tool gives you the best of both worlds. The code you write is easy to maintain, and the code that the tool generates uses the DataColumn object. Figure 9-5 shows the code that the XML Schema Definition Tool generates to return the value of the CompanyName column in a Customers row. Through the miracles of cut and paste, the figure shows the code generated in both Visual Basic .NET and Visual C# .NET.

Figure 9-5

Code from the strongly typed DataSet class that accesses the CompanyName column from a Customers row

You can achieve comparable performance by accessing the contents of a column using a DataColumn object, as shown in the following code:

Visual Basic .NET

Dim dsUntyped As New DataSet() 'Initialize and fill DataSet. Dim tblCustomers As DataTable = dsUntyped.Tables(0) 'Get a reference to the desired column. Dim colCompanyName As DataColumn colCompanyName = tblCustomers.Columns("CompanyName")  Dim row As DataRow = tblCustomers.Rows(0) txtCompanyName.Text = CType(row(colCompanyName), String)

Visual C# .NET

DataSet dsUntyped = new DataSet(); //Initialize and fill DataSet. DataTable tblCustomers = dsUntyped.Tables[0]; //Get a reference to the desired column. DataColumn colCompanyName; colCompanyName = tblCustomers.Columns["CompanyName"];  DataRow row = tblCustomers.Rows[0]; txtCompanyName.Text = (string) row[colCompanyName];

This brings up an important point. There's nothing in the code for the strongly typed DataSet object's class that you can't write yourself. In fact, anything a strongly typed DataSet can do, you can do just as well. But writing your own code can take time. To access the contents of an untyped DataSet with the same performance as a strongly typed DataSet, you must avoid performing string-based lookups in your collections. Instead, use index-based lookups or maintain references to the columns in your untyped DataSet.

In the test I described earlier in this section, code that used the strongly typed DataSet was nearly twice as fast as code that used the untyped DataSet. I modified my code slightly to use code that accessed the contents of the row using the appropriate DataColumn object and also used the appropriate type conversion code. The results? The new and improved code that accessed the untyped DataSet was 5 to 10 percent faster than the code that accessed the strongly typed DataSet.

Because of the added overhead that comes with a strongly typed DataSet, creating, filling, and accessing strongly typed DataSet objects takes more time. In tests I've run, untyped DataSet objects provided slightly better performance (usually between 8 and 10 percent) than strongly typed DataSet objects.

Additional Considerations

Strongly typed DataSet objects can simplify your coding and help save a modicum of sanity. Here are a few more matters for you to consider if you decide to use strongly typed DataSet objects.

Making Structural Changes

If you need to change the structure of your strongly typed DataSet by adding or changing some of the DataColumn objects, you have to regenerate your strongly typed DataSet. Keep this in mind if you build a multi-tiered application in which the middle tier returns strongly typed DataSet objects. If you regenerate the strongly typed DataSet that the middle tier returns, you'll also need to rebuild the client application after refreshing the reference to the middle-tier object. However, if you're going to change the structure of the data returned by your server, you'll probably need to change the client code that accesses that structure anyway, regardless of whether you're using strongly typed DataSet objects.

Converting DataSet Objects

Because strongly typed DataSet objects inherit from the standard DataSet class, the following code that accesses a strongly typed DataSet through an untyped DataSet interface is valid:

Visual Basic .NET

Dim dsStrong As New Chapter9() Dim dsUntyped As DataSet dsUntyped = CType(dsStrong, DataSet)

Visual C# .NET

Chapter9 dsStrong = new Chapter9(); DataSet dsUntyped; dsUntyped = (DataSet) dsStrong;

However, you can "promote" an untyped DataSet to a strongly typed DataSet class only if the untyped DataSet was originally created as an instance of that same strongly typed DataSet class. The following code snippet should help clarify this behavior:

Visual Basic .NET

Dim dsStrong1, dsStrong2 As Chapter9 Dim dsUntyped As DataSet 'This code will succeed. dsStrong1 = New Chapter9() dsUntyped = CType(dsStrong1, DataSet) dsStrong2 = CType(dsUntyped, Chapter9) 'This code will throw an exception. dsUntyped = New DataSet() dsStrong2 = CType(dsUntyped, Chapter9)

Visual C# .NET

Chapter9 dsStrong1, dsStrong2; DataSet dsUntyped; //This code will succeed. dsStrong1 = new Chapter9(); dsUntyped = (DataSet) dsStrong1; dsStrong2 = (Chapter9) dsUntyped; //This code will throw an exception. dsUntyped = new DataSet(); dsStrong2 = (Chapter9) dsUntyped;

What if you have an untyped DataSet and you want to access its contents using a strongly typed DataSet class? If the untyped DataSet object was created as an untyped DataSet, you cannot cast the object to a strongly typed DataSet. However, you can use the Merge method of the strongly typed DataSet to import the data from the untyped DataSet, as the following code snippet illustrates:

Visual Basic .NET

Dim dsStrong As New Chapter9() Dim dsUntyped As New DataSet() dsStrong.Merge(dsUntyped)

Visual C# .NET

Chapter9 dsStrong = new Chapter9(); DataSet dsUntyped = new DataSet(); dsStrong.Merge(dsUntyped);

The Merge method is also useful if you need to move data back and forth between instances of two different strongly typed DataSet classes. You can also use the WriteXml and ReadXml methods to move data back and forth between different strongly typed DataSet classes if you include the XML schema in the calls to WriteXml and ReadXml.

Untyped Features of Strongly Typed DataSet Objects

Let's say your application uses strongly typed DataSet objects and you want to send a DataSet back to your middle-tier server to submit changes to your database. You can use the strongly typed DataSet object's GetChanges method to create a new DataSet that contains only modified rows. However, the GetChanges method returns an untyped DataSet. Can you cast the untyped DataSet returned by the GetChanges method to a strongly typed DataSet? Absolutely. The following code snippet demonstrates this functionality:

Visual Basic .NET

Dim dsStrongAllRows As New Chapter9() 'Fill the strongly typed DataSet and modify some of its rows. Dim dsUntyped As DataSet dsUntyped = dsStrongAllRows.GetChanges() Dim dsStrongModifiedRows As Chapter9 dsStrongModifiedRows = CType(dsUntyped, Chapter9)

Visual C# .NET

Chapter9 dsStrongAllRows = new Chapter9(); //Fill the strongly typed DataSet and modify some of its rows. DataSet dsUntyped; dsUntyped = dsStrongAllRows.GetChanges(); Chapter9 dsStrongModifiedRows; dsStrongModifiedRows = (Chapter9) dsUntyped;

The strongly typed DataSet has other methods that return untyped data. For example, the Select method returns an array of DataRow objects. You can't cast the array to an array of strongly typed DataRow objects, but you can cast the individual DataRow objects to their strongly typed counterparts.

Similar rules apply to the DataView. You can't access its contents directly through the strongly typed classes, but you can convert the DataRow returned by the DataRowView object's Row property to a strongly typed class using the code in the following code snippet:

Visual Basic .NET

Dim dsStrong As New Chapter9() 'Fill the strongly typed DataSet and modify some of its rows. Dim vueCustomers As New DataView(dsStrong.Customers) Dim rowCustomer As Chapter9.CustomersRow rowCustomer = CType(vueCustomers(0).Row, Chapter9.CustomersRow)

Visual C# .NET

Chapter9 dsStrong = new Chapter9(); //Fill the strongly typed DataSet and modify some of its rows. DataView vueCustomers = new DataView(dsStrong.Customers); Chapter9.CustomersRow rowCustomer; rowCustomer = (Chapter9.CustomersRow) vueCustomers(0).Row;

Choosing Your Path

So, what's the right choice for you? Strongly typed DataSet objects can help you build your application more quickly. They can also help you to write efficient code more easily. But they don't offer the best possible performance. You can build an application that will run faster if you use untyped DataSet objects along with intelligent code.

It all depends on the needs of your application. If the performance of your application is the absolute highest priority, you should use only untyped DataSet objects. However, if saving a few hours of development time is worth a small performance hit, you should consider using strongly typed DataSet objects.



Microsoft ADO. NET Core Reference
Microsoft ADO.NET (Core Reference) (PRO-Developer)
ISBN: 0735614237
EAN: 2147483647
Year: 2002
Pages: 104
Authors: David Sceppa

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