Fill a Datatable from a list of a complex type

Asked

Viewed 1,194 times

3

I’m looking to create a method that gets a list of some kind of complex List<T> and return a datatable with all the data. In my code I managed to get 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[]
    }
}

Notice that on the first foreach I used Reflection to create the columns, but now I don’t know how to fill in the data.

2 answers

4

Besides catching the PropertyType you have to check if he is Nullable, so I slightly modified your first is to make this check and add when needed.

To create the rows just create an array in the same sequences that created the columns of the DataTable and then add this 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;
}
  • I didn’t understand the need to check if it is Nullable

  • 1

    @Matheussaraiva For example, if your field is a int or a datetime and vc trying to set a null value on them will give error, because these fields by default do not accept null values unless they are declared as Nullable and when you check only the type does not inform if that field accepts it

  • @Jefersonalmeida well observed on Nullable (adjusted my answer, I hope you don’t mind), but to fill in what is null in the DataRow have to use DBNull.Value or else you’ll be mistaken.

  • Ok, I understood in the code of Xará @Mateus. Is that in your example the variable var type is not used. Thanks for the observation about the possibility of being nullable.

  • @Matheussaraiva was wrong, I forgot to use it, I’ll adjust my code

3


The same way you used Reflection to recover generic type properties, you can also use Reflection to recover the value of the property 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 with the placement of @Jeferson Almeida on Nullable because I remember I’ve had problems with that in the past.

Sources:
Get Property value from string using Reflection in C#
LINQ: IENUMERABLE TO DATATABLE

Browser other questions tagged

You are not signed in. Login or sign up in order to post.