Tuesday, November 30, 2010

Generating a Nullable ADO.NET DataSet Wrapper

Part 2: Describing the DataSet

The next thing I need for code generation is a reliable source of meta data describing the code I want to generate. Here I merely ask the DataSet to describe itself and store the description into a set of simplified description objects. I am moving the metadata from the DataSet into a simpler object to make it easier to deal with when I start generating code in later parts of this series.

public static DataSetDef GetDataSetDefFromDS(DataSet ds) 
{ 
    // Code for this class is in “The Describer Classes” section below 
    var dsDef = new DataSetDef(ds.DataSetName, ds.Namespace); 
    // The DataSet has a collection of DataTables 
    foreach (var rawTable in ds.Tables) 
    { 
        DataTable tab = (DataTable)rawTable; 
        // See “The Describer Classes” 
        var tabDef = new TableDef(tab.TableName); 
        // And each DataTable has a collection of DataColumns 
        foreach (var rawColumn in tab.Columns) 
        { 
            DataColumn col = (DataColumn)rawColumn; 
            // See “The Describer Classes” 
            var colDef = new ColumnDef(col.ColumnName, col.DataType, col.AllowDBNull); 
            tabDef.ColumnDefList.Add(colDef); 
        } 
        dsDef.TableDefList.Add(tabDef); 
    } 
    return dsDef; 
} 

Getting the DataSet to Interrogate

OK, I can generate a description of the data from a DataSet, but the DataSet is in a different project. I want to make a tool that I can use

XSD Schema File

When you create a typed DataSet in Visual Studio, creates a .xsd file that it uses to generate your DataSet code. I can read the schema from an XSD file into a DataSet using the ReadXmlSchema() method:

public static DataSetDef GetDataSetDefFromXsd(string XsdPath) 
{ 
    DataSet ds = new DataSet(); 
    try 
    { 
        ds.ReadXmlSchema(XsdPath); 
        // Call the method above: 
        return GetDataSetDefFromDS(ds); 
    } 
    catch // I don’t care what it is right now 
    { 
        return null; 
    } 
} 

In an Assembly

The DataSet may exist in a previously existing assembly; we may not even have access to the source code. Using reflection, we can activate the type and cast it as a DataSet:

public static DataSetDef doRefelctDataSetFromType(Type myObjectType) 
{ 
    // Create an instance of the Type: 
    object obj = Activator.CreateInstance(myObjectType); 
    // Try to cast it as a DataSet: 
    DataSet ds = obj as DataSet; 
    if (ds != null) 
    { 
        // Call the method above: 
        return GetDataSetDefFromDS(ds); 
    } 
    return null; 
} 

The Describer Classes

These are the classes to make the objects loaded in GetDataSetDefFromDS(). They represent a simplified description of the data. I only get the data that I think I need to generate the code later. If I later need more data, I can alter GetDataSetDefFromDS() and these classes add what I need.

public class DataSetDef 
{ 
    public List TableDefList { get; private set; } 
    public DataSetDef() 
    { 
        TableDefList = new List(); 
    } 
    public DataSetDef(string dataSetName, string nameSpace) : 
        this() 
    { 
        DataSetName = dataSetName; 
        NameSpace = nameSpace; 
    } 
    public string DataSetName { get; set; } 
    public string NameSpace { get; set; } 
} 
public class TableDef 
{ 
    public List ColumnDefList { get; private set; } 
    public TableDef() 
    { 
        ColumnDefList = new List(); 
    } 
    public TableDef(string tableName) : 
        this() 
    { 
        TableName = tableName; 
    } 
    public string TableName { get; set; } 
} 
public class ColumnDef 
{ 
    public ColumnDef(string columnName, Type dataType, bool allowDBNull) 
    { 
        ColumnName = columnName; 
        DataType = dataType; 
        AllowDBNull = allowDBNull; 
    } 
    public string ColumnName { get; set; } 
    public Type DataType { get; set; }  // .NET Type, not SQL Type 
    public bool AllowDBNull { get; set; } 
} 

Generating a Nullable ADO.NET DataSet Wrapper: The Series

No comments: