To enhance aggregation and delivery of data across the tiers of distributed enterprise systems, ADO.NET introduces a new breed of object that looks and acts like the in-memory version of a modern powerful database the DataSet. At its core, the DataSet is merely a data container a sort of super dictionary specifically designed to manage tabular data expressed in terms of tables, columns, and rows. Nothing in the DataSet is tied to a physical database be it Microsoft SQL Server, Microsoft Office Access, or even Oracle databases. The DataSet has no notion of the provider that served its data; it is a mere data container that is serializable, feature-rich, and tightly integrated with ADO.NET providers. DataSet and related objects such as DataTable, DataView, and DataRelation form the second leg of the ADO.NET framework that is, smart containers of data filled by enabled managed providers.
ADO.NET containers expose an API to let application developers populate them with any sort of data. In many cases, though, you want a DataSet to contain the results of a database query. This entails various steps: running the query, processing the results, filling the container, closing the connection. To get the results, you need a command and a data reader; next, you need some code to walk through the reader and copy the records in a proper table layout. All this behavior (and much more, actually) is incorporated in a made-to-measure ADO.NET object the data adapter. Without further adieu, let's start the second part of our ADO.NET exploration with a look at adapters. Next, we'll take the plunge and dive into the DataSet, DataTable, and DataView classes. As their names suggest, these classes mimic the behavior of well-known database objects but remain database-agnostic that is, they remain as purely in-memory objects.