Neste Post, vou demonstrar como podemos gerar um DataTable a partir de uma query realizada com o LINQ utilizando ADO Data Entity.
Em determinadas situações como uma migração de sistema, por exemplo, necessitamos adaptar nosso código para trabalhar da maneira mais transparente possível e causando um menor impacto na aplicação. Vou dar um exemplo. Imagine uma aplicação onde a camada de dados faz um acesso a base e monta um DataTable devolvendo para a aplicação consumir. Nesta aplicação temos a necessidade de fazer uma migração para ADO.NET Entity Framework. Seria um impacto muito grande se, a princípio, tentássemos migrar a camada de dados e a aplicação junto para que, ao invés de DataTable, a aplicação passe a receber objetos do Entity Framework. Para isso, desenvolví uma pequena rotina para gerar DataTable a partir de uma query LINQ no Entity Framework.
A primeira parte é a query com o LINQ:
AdventureWorksEntities db = new AdventureWorksEntities(); IQueryable _query = (from c in db.Address where c.City.Equals("Bothell", StringComparison.CurrentCultureIgnoreCase) select new { ID = c.AddressID, Endereco = c.AddressLine1, Cidade = c.City, CaixaPostal = c.PostalCode } ).OrderBy(o=>o.Endereco);
Reparem que no Retorno eu recebo um objeto do tipo IQueryable. Ele é uma interface que guarda os dados da query como: provider, expressão e os tipos de elemento que são retornados quando a expressão é executada. Como o retorno da query por definição implementa IQueryable, esta atividade fica transparente. O IQueryable também implementa IEnumerable, o que possibilita também percorrer a lista retornada pela query.
Eis o Método que transforma o objeto IQueriable em DataTable:
public static DataTable RetornarDataTable(IQueryable pObjQuery) { DataTable _dt = new DataTable(); //Cria o DataTable foreach (var item in pObjQuery) { Type t = item.GetType(); PropertyInfo[] properties = t.GetProperties(); for (int i = 0; i < properties.Length; i++) { _dt.Columns.Add(properties[i].Name); } break; } IEnumerator en = (IEnumerator)pObjQuery.GetEnumerator(); //Popula o DataTable while (en.MoveNext()) { Type ten = en.Current.GetType(); PropertyInfo[] propertiesen = ten.GetProperties(); DataRow _dtrow = _dt.NewRow(); for (int i = 0; i < propertiesen.Length; i++) { object obj = propertiesen[i].GetValue(en.Current, new object[] { }); _dtrow[i] = obj; } _dt.Rows.Add(_dtrow); } return _dt; }
Reparem que neste código, procurei separar a montagem do DataTable, inclusive com os nomes das colunas fiéis a query, e logo após percorro a lista carregando os registros.
Abaixo o Código Completo para Testes:
static void Main(string[] args) { DataTable _dtEnderecos = RetornarEnderecos(); foreach (DataColumn col in _dtEnderecos.Columns) { Console.WriteLine(col.ColumnName); } Console.WriteLine(""); foreach (DataRow dados in _dtEnderecos.Rows) { Console.WriteLine(dados["ID"] + " " + dados["Endereco"] + " " + dados["Cidade"] + " " + dados["CaixaPostal"]); } Console.Read(); } public static DataTable RetornarEnderecos() { AdventureWorksEntities db = new AdventureWorksEntities(); IQueryable _query = (from c in db.Address where c.City.Equals("Bothell", StringComparison.CurrentCultureIgnoreCase) select new { ID = c.AddressID, Endereco = c.AddressLine1, Cidade = c.City, CaixaPostal = c.PostalCode } ).OrderBy(o=>o.Endereco); return RetornarDataTable(_query); } public static DataTable RetornarDataTable(IQueryable pObjQuery) { DataTable _dt = new DataTable(); //Cria o DataTable foreach (var item in pObjQuery) { Type t = item.GetType(); PropertyInfo[] properties = t.GetProperties(); for (int i = 0; i < properties.Length; i++) { _dt.Columns.Add(properties[i].Name); } break; } IEnumerator en = (IEnumerator)pObjQuery.GetEnumerator(); //Popula o DataTable while (en.MoveNext()) { Type ten = en.Current.GetType(); PropertyInfo[] propertiesen = ten.GetProperties(); DataRow _dtrow = _dt.NewRow(); for (int i = 0; i < propertiesen.Length; i++) { object obj = propertiesen[i].GetValue(en.Current, new object[] { }); _dtrow[i] = obj; } _dt.Rows.Add(_dtrow); } return _dt; }
A codificação é relativamente simples e de fácil implementação.
Até a Próxima...