Paginação utilizando LINQ

Podemos facilmente vincular uma query LINQ em um controle DataBound do ASP.NET para exibir os dados. A query pode ser feita utilizando LINQ To SQL, LINQ To Xml, etc. Com isso, podemos simplesmente fazer:

this.GridView1.DataSource = from cliente in colecaoDeClientes select cliente;
this.GridView1.DataBind();

Os problemas aparecem quando voce habilita a paginação do controle e, ao rodar o mesmo exemplo, uma exceção do tipo NotSupportedException será disparada, informando a seguinte mensagem: The data source does not support server-side data paging. Quando efetuamos uma query LINQ (em cima de qualquer fonte de informação), o retorno é sempre uma classe que implementa direta ou indiretamente a Interface IEnumerable<T>, e para efetuar a paginação, é necessário que o controle conheça a quantidade de registros retornados pela query para conseguir dimensionar a quantidade necessária de páginas a serem exibidas.

A Interface referida acima não possui uma propriedade que informe a quantidade de elementos da coleção e, como alternativa, podemos alterar a query para que ela retorne uma instancia da classe List<T>, modificando ligeiramente a query:

this.GridView1.DataSource = (from cliente in colecaoDeClientes select cliente).ToList();
this.GridView1.DataBind();

Acessando tipos anônimos no evento RowDataBound

Há algum tempo eu mostrei como acessar o item que está sendo adicionado em um controle DataBound para fazer algum tipo de verificação durante a inserção dos dados no controle. Como é mostrado no post, a conversão deve ser feita de acordo com o tipo de fonte de dados que está sendo inserida no controle (DataTable, DataReader, objetos, etc). Mas e quando precisamos acessar um tipo anônimo que é projetado a partir de uma query LINQ?

this.GridView1.DataSource = from cliente in colecaoDeClientes
                            select new
                            {
                                Nome = cliente.Nome,
                                QualquerOutraInformacao = true
                            };
this.GridView1.DataBind();

No exemplo acima, não há um tipo efetivo em que podemos converter o DataItem que é passado como parametro para o evento, impossibilitando extrair o valor de uma determinada propriedade. Para contornar esse problema, podemos recorrer ao método estático Eval da classe DataBinder, passando o DataItem como parametro e o nome da propriedade a ser recuperada. O exemplo abaixo mostra como efetuar o acesso ao tipo anônimo no evento RowDataBound do controle GridView:

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        ((Button)e.Row.FindControl(“btn”)).Enabled =
            Convert.ToBoolean(DataBinder.Eval(e.Row.DataItem, “QualquerOutraInformacao”));
    }
}

Além de ser uma técnica late-bound e que usa Reflection em runtime, ainda há o problema de ser fracamente tipado, o que nos obriga a sempre efetuar a conversão explícita para garantir a compilação da aplicação.

Múltiplas condições no JOIN com LINQ

Em minhas deambulações com o LINQ, me surgiu uma dúvida de como proceder para efetuar um join com duas condições na cláusula on. Inicialmente tentei da forma mais fácil, ou seja, utilizando o operador &&, mas sem muito sucesso. Com um pequena busca, encontrei um post no MSDN em que o próprio Anders Hejlsberg explica como proceder. Simplesmente basta criarmos um tipo anônimo e combinarmos os campos que desejamos comparar, assim como é mostrado no exemplo abaixo:

from sala in cadastroDeSalas
join curso in Cursos on
    new
    {
        cadastroDeSalas.Campo1,
        cadastroDeSalas.Campo2
    }
    equals 
    new 
    {
        curso.Campo1,
        curso.Campo2 
    }