Fill a DataTable from a list of a complex type

3

I want to create a method that receives a list of a complex type any List<T> and returns a DataTable with all the data. In my code I got here.

protected virtual DataTable buildDataTableFromComplexTypeList<T> ( string tableName, List<T> complexList )
{
    DataTable dataTable = new DataTable ( tableName );
    PropertyInfo[] properties = typeof ( T ).GetProperties ( ); // Getting the metadata through reflection (System.Reflection)

    foreach ( PropertyInfo property in properties ) // Create DataTableColumns from the T properties
        dataTable.Columns.Add ( property.Name, property.PropertyType );

    DataRow dataRow;

    foreach ( T item in complexList )
    {
        dataRow = dataTable.NewRow ( ); // Create new DataRow with the same columns of DataTable
        dataRow[]
    }
}

Please note that in the first foreach I used Reflection to create the columns, but now I do not know how to fill in the data.

    
asked by anonymous 17.02.2017 / 22:43

2 answers

2

Just as you used Reflection to retrieve generic type properties, you can also use Reflection to retrieve the property value for an instance of that type, it would look like this:

protected virtual DataTable buildDataTableFromComplexTypeList<T>(string tableName, List<T> complexList)
{
    DataTable dataTable = new DataTable(tableName);
    PropertyInfo[] properties = typeof(T).GetProperties(); // Getting the metadata through reflection (System.Reflection)

    foreach (PropertyInfo property in properties) // Create DataTableColumns from the T properties
    {
        var type = (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(property.PropertyType) : property.PropertyType);
        dataTable.Columns.Add(property.Name, type);
    }

    DataRow dataRow;

    foreach (T item in complexList)
    {
        dataRow = dataTable.NewRow(); // Create new DataRow with the same columns of DataTable
                                        // novas linhas
        foreach (PropertyInfo property in properties)
            dataRow[property.Name] = property.GetValue(item) ?? DBNull.Value;

        dataTable.Rows.Add(dataRow);
    }

    // nova linha
    return dataTable;
}

If you want, you can do the same using Linq

protected virtual DataTable buildDataTableFromComplexTypeList<T>(string tableName, List<T> complexList)
{
    DataTable tabela = new DataTable();
    PropertyInfo[] propriedades = typeof(T).GetProperties();

    tabela.Columns.AddRange(
        propriedades.Select(p => new DataColumn(p.Name, (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(p.PropertyType) : p.PropertyType))).ToArray()
        );

    complexList.ForEach(
        i => tabela.Rows.Add(
            propriedades.Select(p => p.GetValue(i) ?? DBNull.Value).ToArray()
            )
        );

    return tabela;
}

I adjusted the answer by placing @Jeferson Almeida on Nullable because I remember that I have had problems with this in the past.

Sources:
LINQ: IENUMERABLE TO DATATABLE

    
18.02.2017 / 02:14
3

In addition to getting the PropertyType you have to check that it is Nullable , so I modified your first for a bit to do this check and add it when needed.

To create the rows just create an array in the same sequence that created the columns of DataTable and then add that array with the following command dataTable.Rows.Add(array)

protected virtual DataTable buildDataTableFromComplexTypeList<T>(string tableName, List<T> complexList)
{
    DataTable dataTable = new DataTable(tableName);
    PropertyInfo[] properties = typeof(T).GetProperties(); 

    foreach (PropertyInfo property in properties)
    {
        var type = (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(property.PropertyType) : property.PropertyType);
        dataTable.Columns.Add(property.Name, type );

    }

    foreach (T item in complexList)
    {
        var values = new object[properties.Length];
        for (int i = 0; i < properties.Length; i++)
        {
            values[i] = properties[i].GetValue(item, null);
        }
        dataTable.Rows.Add(values);
    }

    return dataTable;
}
    
18.02.2017 / 01:25