views:

275

answers:

2

I have a DataSet with some DataTables that are linked together with DataRelations (classic order Header/Detail pair). Is there an easy way to denormalize the whole lot into a single DataTable with all the columns of the related tables?

The table names and columns are not known at compile time, and there may be more than two tables/relations.

A: 

I don't think data sets support this natively, but it is easy enough to do in code.

First you should create an empty data table and then add all the columns you need from both the tables you want to combine.

Then you step through the data in your main table and step through all related rows from the related table. For each row in the related table you create a new row in your new table and inserts the data from both data rows into the new one.

I don't have access to visual studio here now, but you get the idea.

Rune Grimstad
+2  A: 

Hi,

Had the same problem my self, but since this question didn't have an answer I had to write the denormalizer my self. Turned out it wasn't all that difficult - so this is a first cut that you (or some one else who run into this problem) might be able to use/extend:

public class DataSetDenormalizer
{
    public void DenormalizeRelationships(DataSet dataSet)
    {
        IOrderedEnumerable<DataRelation> orderedRelationship = SortRelationshipsByNumberOfChildRows(dataSet);
        var tablesToRemove = new List<DataTable>();

        foreach (DataRelation relationship in orderedRelationship)
        {
            DenormalizeColumns(relationship);
            DenormalizeData(relationship);
            RemoveDenormalizedRelationships(dataSet, relationship, tablesToRemove);
        }
    }

    private IOrderedEnumerable<DataRelation> SortRelationshipsByNumberOfChildRows(DataSet dataSet)
    {
        var relationships = new List<DataRelation>();
        foreach (DataRelation relationship in dataSet.Relations)
            relationships.Add(relationship);
        return relationships.OrderBy(r => r.ChildTable.Rows.Count);
    }

    private void DenormalizeColumns(DataRelation relationship)
    {
        for (int columnIndex = 0; columnIndex < relationship.ParentTable.Columns.Count; ++columnIndex)
        {
            DataColumn column = relationship.ParentTable.Columns[columnIndex];
            if (relationship.ParentColumns.Contains(column)) continue;
            relationship.ChildTable.Columns.Add(new DataColumn(column.ColumnName, column.DataType));
        }
    }

    private void DenormalizeData(DataRelation relationship)
    {
        for (int rowIndex = 0; rowIndex < relationship.ChildTable.Rows.Count; ++rowIndex)
        {
            DataRow row = relationship.ChildTable.Rows[rowIndex];
            DataRow parentRow = row.GetParentRow(relationship);

            for (int columnIndex = 0; columnIndex < relationship.ParentTable.Columns.Count; ++columnIndex)
            {
                DataColumn column = relationship.ParentTable.Columns[columnIndex];
                if (relationship.ChildTable.Columns.Contains(column.ColumnName))
                {
                    row.SetField(column.ColumnName, parentRow[column]);
                }
            }
        }
    }

    private void RemoveDenormalizedRelationships(DataSet dataSet, DataRelation relationship, List<DataTable> tablesToRemove)
    {
        dataSet.Relations.Remove(relationship);
        relationship.ChildTable.Constraints.Remove(relationship.RelationName);

        if (!tablesToRemove.Contains(relationship.ParentTable))
            tablesToRemove.Add(relationship.ParentTable);

        int numberOfColumns = relationship.ChildColumns.Length;
        for (int columnIndex = 0; columnIndex < numberOfColumns; ++columnIndex)
        {
            relationship.ChildTable.Columns.Remove(relationship.ChildColumns[columnIndex]);
        }
    }
}
Jonas Follesø