Creating DataModule-like components in .NET

Delphi’s DataModules were a useful programming tool because they provided a centralized place to define data schema and business logic which could then be referenced from multiple locations. Visual Studio .NET, however, encourages the programmer to place DataSets and Adapters on each individual page, resulting in decentralized and possibly redundant business logic. However, it is possible to roll your own DataModule-like components in .NET. Here’s how:

  1. Decide whether you want to have your custom DataSet component in the same project or in a class library. Keeping it in the same project is a little simpler, while putting it in a separate class library will result in a separate assembly that contains only data logic, making it more suitable to deploy as a business tier.
  2. Add a new Component to the target project 
  3. Add a Connection and DataAdapters to the Component, and generate a DataSet. The visibility of the Connection and DataAdapters will default to private, so make sure to change them as appropriate for your design.
  4. Once the DataSet has been generated, create a new class that descends from the DataSet subclass. The DataSet subclass name is the same as the name of the .xsd schema file.
  5. Add the following attributes to your DataSet subclass:
    1. [ Serializable() ]
    2. [ System.ComponentModel.ToolboxItem( true ) ]
  6. Add a property to the DataSet subclass that references the Component containing all the DataAdapters. Include logic either in the DataSet subclass constructor or in the property accessor to create a new instance of the DataAdapter container if needed.
  7. Optionally, to hide the base DataSet class, open the base .cs file with the same name as the schema .xsd file and change the ToolboxItem attribute from true to false. Changes made to this file will disappear every time the .xsd it is based on changes, so make the decision whether or not this step is worthwhile accordingly.
  8. Build the project
  9. You can now add the custom DataSet class to the Toolbar. When dragged into another project, the Visual Studio IDE will treat the DataSet subclass as if it is a DataSet; it will appear as a top-level item in the DataBinding dialog box and have the DataSet property editor. Additionally, all the custom business logic methods you added to the class will also be available in code. The DataSet schema will only be editable in the project containing the DataSet subclass, which is a natural result of centralizing your schema and logic. Be forewarned that adding such a custom DataSet to the Toolbar while it is still in development might cause more frustration than it’s worth, since Visual Studio will not be easily persuaded to detect changes to the DataSet schema, particularly in the designer.

Sample Code

using System;

namespace MyNamespace.MyDataModules
{

  [ Serializable() ]
  [ System.ComponentModel.ToolboxItem( true ) ]
// MyStronglyTypedDataSet is the name of the DataSet class
// automatically generated by Visual Studio .NET
public class CustomDataSet : MyStronglyTypedDataSet
  {

// CustomDataSetAdapters is the name of the Component class

// containing all the DataAdapters used to generate, fill,

// and update the DataSet.

private CustomDataSetAdapters _Adapters;
private System.ComponentModel.Container components = null;
public CustomDataSet( System.ComponentModel.IContainer container )
    {
      container.Add( this );
      InitializeComponent();
// Initialize DataSet properties here

_Adapters = new CustomDataSetAdapters( container );
    }
public CustomDataSet()
    {
// Initialize DataSet properties here

­_Adapters = new CustomDataSetAdapters();
    }
protected override void Dispose( bool disposing )
    {
if ( disposing )
      {
if ( components != null )
        {
          components.Dispose();
        }
      }
base.Dispose( disposing );
    }

// This property exposes the component class containing

// all the DataAdapters used to generate, fill, and update

// the DataSet

public CustomDataSetAdapters Adapters

{

get

{

return _Adapters;

}

}
public void BusinessLogicMethod1()
    {
// Custom business logic here
    }
  }
}