Pergunta

Eu tenho um DataSet com algumas tabelas de dados que estão ligados entre si com DataRelations (ordem clássica cabeçalho / Detalhe par). Existe uma maneira fácil de desnormalizar todo o lote em um único DataTable com todas as colunas das tabelas relacionadas?

Os nomes de tabelas e colunas não são conhecidos em tempo de compilação, e pode haver mais de duas tabelas / relações.

Foi útil?

Solução

teve o mesmo problema meu eu, mas desde que esta pergunta não tem uma resposta que eu tinha que escrever o denormalizer minha auto. Acabou por não era tão difícil - por isso este é um primeiro corte que você (ou alguma outra pessoa que executar para esse problema) pode ser capaz de uso / 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]);
        }
    }
}

Outras dicas

Eu não acho que os conjuntos de dados suportam isso nativamente, mas é fácil o suficiente para fazer no código.

Primeiro, você deve criar uma tabela de dados vazia e, em seguida, adicionar todas as colunas que você precisa de ambas as tabelas que você deseja combinar.

Então você percorrer os dados na sua tabela principal e passo através de todas as linhas relacionadas da tabela relacionada. Para cada linha na tabela relacionada você cria uma nova linha na sua nova tabela e insere os dados de ambas as linhas de dados para o novo.

Eu não tenho acesso ao visual studio aqui agora, mas você começa a idéia.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top