Change the base class of a TableAdapter in a typed DataSet

Page updated :

Code to create and generate a typed DataSet

A typed DataSet allows you to create a DataTable that has type information for each column based on SQL, or a TableAdapter that simplifies data interaction with DB based on a typed DataTable.

Since the purpose is not to create a typed DataSet here, let's quickly create a DataSet with the database and table ready for now. You can also do whatever you want to lay out the table.

The first step is to add a DataSet as a new item to your project. The name is anything but it is left here.

Open the DataSet and add a TableAdapter from the designer.

Follow the wizard to create a DataTable and A TableAdapter.

I think that the following form might be an example of retrieving and using records from the database using the DataTable and TableAdapter that you created. (This is just an example.)

public Form1()
{
  InitializeComponent();

  using (var adapter = new 金額集計TestTableAdapter())
  {
    var table = adapter.GetData();

    foreach (var row in table)
    {
      Trace.WriteLine(string.Format("{0}:{1}", row.年月, row.金額));
    }
  }
}

Typically, a project that uses this DataSet has fewer than one table, and you create many DataSets that combine the number of tables or multiple tables. I think that it is a common ization of the processing to come up when it happens. For example, you might want to dynamically change the SQL used internally to change the conditions for retrieving records.

However, the TableAdapter class created from the DataSet is actually automatically generated by the code. Also, because this TableAdapter class inherits the Component class, there are no methods or properties that can be used in real common. You cannot pass a base class to a method to call a tableadapter-related operation.

In addition, sql used internally, sqldataadapter used to access the database, etc. are declared in protected, so you cannot touch them from the outside.

However, as you declare for methods and properties declared in protected, you can touch them by creating a class that inherits the TableAdapter class, and this TableAdapter class has a partial modifier, so you can declare another method or property to extend the process. You can also create a new property to get the internal property, as in the following code:

using System.Data.SqlClient;
namespace DataSetBaseAdapter {
    public partial class DataSet1 {
    }
}

namespace DataSetBaseAdapter.DataSet1TableAdapters
{
  public partial class 金額集計TestTableAdapter
  {
    public SqlDataAdapter InnerAdapter
    {
      get { return Adapter; }
    }
  }
}

You can actually use this TableAdapter to see that you have access to the extended properties.

However, accessing internal properties does not mean that the process is common, and you still have to write code for each DataSet you create.

Change the base class of a TableAdapter

As mentioned earlier, the TableAdapter class inherits the Component class, making it difficult to share processing. If you change the part of code that inherits a class, the code is auto-generated, so updating the DataSet again returns the code. If you can, you can write a partial class that inherits interface in a separate file, but it doesn't make much sense because you have to write as many TableAdapters as you've created.

In fact, there is a mechanism to change the inheriting class of this TableAdapter. I'd like to explain the procedure.

First, create the class you want to inherit. TableAdapter originally inherited the Component class, so you should inherit the Component class even if you create it. I'll write the code i want to share here, but i'll just write a class. Match the namespace to what you created.

using System.ComponentModel;

namespace DataSetBaseAdapter
{
  public class BaseAdapter : Component
  {
  }
}

Then open the DataSet designer and select the TableAdapter that you created.

Right-click to open the property. There is a property called BaseClass, which should initially be "System.ComponentModel.Component". Rewrite this to the class you just created. I'll write everything, including the namespace.

If you save it, you'll see that the base class of the TableAdapter has changed. By setting this to each TableAdapter, you can write common processing to the base class.

For example, if you want to access an internal SQL or SQLDataAdapter, write: Adapters and CommandCollections that are created automatically are only properties created by the inheritor class, so they cannot be touched directly from the inheritor. The following code uses reflection to force access.

using System.ComponentModel;
using System.Data.SqlClient;
using System.Reflection;

namespace DataSetBaseAdapter
{
  public class BaseAdapter : Component
  {
    public SqlDataAdapter InnerAdapter
    {
      get
      {
        return (SqlDataAdapter)GetType().GetProperty("Adapter",
          BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this, null);
      }
    }

    public SqlCommand[] InnerCommandCollection
    {
      get
      {
        return (SqlCommand[])GetType().GetProperty("CommandCollection",
          BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this, null);
      }
    }
  }
}

You can see that you can actually use the TableAdapter to access the properties of the inherited class.