Introducción
En este post vamos a ver como llevar a cabo la exportación de un objeto IEnumerable<T> a un DataTable. Pero, espera!!! Ya existe un método extensor CopyToDataTable, que parece realizar esta acción.
Todo parece que sí, pero parece demasiado bonito. Si nos fijamos en la firma del método:
1: public static DataTable CopyToDataTable<T>(
2: this IEnumerable<T> source
3: )
4: where T : DataRow
Veremos que este método, solo lo podremos utilizar en el caso de que T sea de tipo DataRow o implemente a DataRow.
Bueno, el porque del post es debido a una preguntaba que lanzó ayer en Twitter @Zpektrum, sobre porque no podía utilizar dicho método con una consulta Linq.
Código:
Para ilustrar el ejemplo vamos a ver una query linq contra un DataTable:
1: var query = from t in dt1.AsEnumerable()
2: select new
3: {
4: ID = t.Field<string>("ID"),
5: Nombre = t.Field<string>("Name")
6: };
Como podeís apreciar estamos realizando una consulta sobre las filas de la tabla dt1, y escogiendo las columnas ID y Nombre. El resultado de esta consulta va a devolver un IEnumerable<T> donde T va a ser un tipo anónimo, por lo que dicho tipo no va a ser DataRow y no vamos a tener disponible el método CopyToDataTable.
Bien, para construir nuestro nuevo método extensor, tendremos que definir una nueva clase estática y un método estático que retorne un objeto de Tipo DataTable, y haremos que el método sea genérico.
1: public static class IEnumerableExtensions
2: {
3: public static DataTable CopyAnonymusToDataTable<T>(this IEnumerable<T> info)
4: {
5: var type = typeof(T);
6: if (type.Equals(typeof(DataRow)))
7: return (info as IEnumerable<DataRow>).CopyToDataTable();
8: DataTable dt = new DataTable();
9: DataRow r;
10: type.GetProperties().ToList().ForEach(a=> dt.Columns.Add(a.Name));
11: foreach (var c in info)
12: {
13: r = dt.NewRow();
14: c.GetType().GetProperties().ToList().ForEach(a => r[a.Name] = a.GetValue(c,null));
15: dt.Rows.Add(r);
16: }
17: return dt;
18: }
19:
20: }
Para que el método sea un método extensor es necesario que sea estático, que este contenido en una clase estática y que su primer parámetro tenga el modificador “this” y el tipo que va a extender.
Explicando el método:
El método es sencillo, en primer lugar comprobamos que si el tipo de T es DataRow que ejecute el método CopyToDataTable ya existente.
En caso contrario, a través de reflectión obtendremos las propiedades del Tipo T, e iremos definiendo nuevas columnas con el nombre de dichas propiedades en la tabla resultante.
Por último, iteraremos sobre el contenido de la colección e iremos agregando las filas para devolverlos.
Ejecución del método:
Continuando con el ejemplo anterior:
1: var query = (from t in dt1.AsEnumerable()
2: select new
3: {
4: ID = t.Field<string>("ID"),
5: Nombre = t.Field<string>("Name")
6: }).CopyAnonymusToDataTable();
De está manera query, será de tipo DataTable y ya podremos manejar dicha tabla a nuestro gusto.
Un saludo y espero que os sea de utilidad.