Monday, September 25, 2006

DataSets vs. Business Objects

ATTENTION: The following words are picked out with my respect from Mr. Brian Noyes's essay Build a Data Access Layer with Visual Studio 2005 DataSet Designer publish at theserverside.net http://www.theserverside.net/tt/articles/showarticle.tss?id=DataSetDesigner

Almost as common as the debate over which .NET language to choose is the argument about whether to use DataSets or not. As described above, typed data sets are easy to generate through the designer, provide a type safe API for containing business entity data, and already support advanced features such as change tracking, sorting, filtering, and searching. Some of the resistance to DataSets resulted from several performance shortcomings in the .NET 1.1 implementations. These problems included poor performance when working with large DataSets and the fact that DataSets always serialized themselves as XML, which had bandwidth and performance implications when passing DataSets across remoting boundaries. These problems have been fixed in .NET 2.0 and there have been a large number of other improvements. If you dismissed DataSets in .NET 1.1, they deserve another look.

The alternative to using DataSets is to create custom object types that represent your business entities, and custom collection types to contain them. When you go this route, you end up needing to write a lot more code yourself. This has gotten a lot better in Visual Studio 2005 and .NET 2.0 with the additions of code snippets and generic collection classes. But to support the full range of features that a DataSet provides, there is still a fair amount of custom code that you will need to write by hand.

Custom objects have the advantage of giving you explicit and complete control over the way the type is designed, what its internal capabilities are, and what the API is that is exposed from the object. If you prefer a pure object-oriented design approach, then custom business entities will feel a little more comfortable to you. You can accomplish almost anything with a typed data set that you can with a custom business entity, but some things may be a little less clean with a typed data set if the things you are trying to do don’t map well to the relational nature of a typed data set. But if you are primarily getting business data for the purposes of presenting the data, allowing the user to work with the data, and then will persist the data back to the database, you will be able to get things done quicker with typed data sets if you harness the features of the DataSet designer.

When you work with data in an application, the data is usually partitioned into different types of logical business entities, such as Customers, Products, Employees, and so on. To work with that data, you need to encapsulate those logical entities into objects that you can deal with in your code. You could write a custom class for each entity type. Those entity types would expose properties for each of the data values that the entity includes. You would then also want to create a custom collection type for each entity type so that you could have strongly typed collections to contain those entities.

Typed data sets represent an easy alternative to creating and maintaining all those custom types yourself. Essentially what you are doing when you create a typed data set is that you are creating a set of custom type definitions to contain logical business entities and collections of those entities, similar to writing those types by hand. The difference is that you are doing it in a declarative way through the designer that is easy to visualize, edit, and keep synchronized with the database schema that populates those business entities. The code generation of Visual Studio takes care of writing all the underlying properties and methods that give you a strongly typed API for dealing with those business entities in your consuming code. Additionally, because these types are inheriting from the ADO.NET types, you inherit the rich relational data manipulation functionality from those types. These types are also aligned well with the data binding capabilities in Windows Forms and ASP.NET, so if you will be setting up data binding using the objects, then you have less work to do on that front as well.

Finally, and perhaps most importantly, when you create typed data sets in Visual Studio 2005 from a database, you also get a table adapter type created for each table that you add to the data set. A table adapter is a full fledged data access component that lets you retrieve and update data from the database. It encapsulates a connection, a data adapter, and a set of command objects that allow you to execute queries to the database. I’ll get into more detail on table adapters in a little bit.

When you go with typed data sets in Visual Studio 2005, you can actually support most of the same design styles that you could with custom business entity types. The data access code will always be separated into the table adapter types generated by the designer, or into data access components that you write. But you can add custom validation and other logic into your business entity types (the typed data row or data table classes) through partial class extensions. Each of the types created as part of a typed data set definition (data set, data table, data row, and table adapter) are defined in the generated code as partial classes. This feature in .NET 2.0 allows you to supplement the designer generated code with custom code that becomes part of the compiled type, but you do so through a separate code file. This prevents your code from being destroyed if you choose to regenerate the designer generated code.

Another argument that comes up a lot against using DataSets is the assertion that if you are using DataSets in your presentation or business layer, then you are tightly coupling your application to the data tier. This does not have to be the case. First off, you should consider using stored procedures as a layer of decoupling between your actual data tier schema and your application. Your stored procedures can then return and work with result sets that map well to the business entities that you will be manipulating in your application. Additionally, if you need to provide additional decoupling beyond what the stored procedures provide, you can transform data that has been placed into a DataSet into either a different (decoupled) typed data set definition or a custom business entity type in your business or data access layer.

The designer allows you to very quickly create customized query methods in the table adapter that makes it so you will rarely have to write any ADO.NET code yourself if you are working with typed data sets.