Este é o quinto post de uma série de posts que estou escrevendo sobre a ASP.NET 4.5.
Os
próximos lançamentos do .NET e Visual Studio incluem vários novos e
ótimos recursos e capacidades. Com a ASP.NET 4.5 você vai ver um monte
de melhorias realmente emocionantes em formulários da Web ( Web Forms )
e MVC - assim como no núcleo da base de código da ASP.NET, no qual
estas tecnologias são baseadas.
O post de hoje é o terceiro de
três posts que falam sobre o novo suporte para Model Binding ( Ligação/Vinculação
do Modelo Dados ) que está chegando para Web Forms. Model Binding é uma
extensão do sistema de data-binding ( ligação de dados ) existente na
ASP.NET Web Forms e fornece um paradigma de acesso a dados focado no
código. Este novo suporte tira proveito de um monte de conceitos
relativos à ligação do modelo que introduzimos pela primeira vez com a
ASP.NET MVC - e os integra muito bem com o modelo de controles do
servidor para Web Forms.
Se você ainda não viu, leia as duas
primeiras partes desta série sobre Model Binding, as quais abrangem os
conceitos básicos sobre Seleção de dados através da nova propriedade SelectMethod em controles de dados como o GridView, e filtragem destes dados com base na entrada do usuário.
No post de hoje veremos como Model Binding melhora a experiência de ligação de dados quando fazemos a atualização destes dados.
Começando
Vamos começar com o exemplo do GridView do post anterior,
configurado para usar Model Binding para mostrar os dados da tabela de
Produtos do banco de dados Northwind. O GridView chama o método
GetProducts, que por sua vez está usando a abordagem Code First do
Entity Framework para simplesmente retornar a propriedade Products da
instância do contexto de dados Northwind.
É importante que a
propriedade DataKeyNames aponte para a chave primária (ou chaves) do
tipo do modelo, para que o GridView possa passar esse valor juntamente
com a página entre o browser e o servidor.
<asp:GridView ID="productsGrid" runat="server" DataKeyNames="ProductID"
ModelType="ModelBindingPart3.Product"
AllowPaging="true" AllowSorting="true" AutoGenerateColumns="false"
SelectMethod="GetProducts">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ID" />
<asp:BoundField DataField="ProductName" HeaderText="Name" SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="# in Stock" SortExpression="UnitsInStock" />
</Columns>
</asp:GridView>
A seguir está o código do nosso arquivo de code-behind (o qual contém o método GetProducts()):
public partial class _Default : Page
{
private Northwind _db = new Northwind();
public IQueryable<Product> GetProducts()
{
return _db.Products;
}
}
Ao executarmos esta página ela produz o resultado esperado em uma tabela que contém os dados dos produtos:

Em
virtude de nosso método GetProducts() estar retornando uma
IQueryable<Product>, os usuários podem facilmente paginar e
ordenar os dados dentro do nosso GridView. Apenas as 10 linhas que são
visíveis em qualquer página do grid são retornadas do banco de dados.
Ativando o Suporte à Edição de Dados
Podemos
ativar a edição de uma linha do GridView ao definirmos o atributo
AutoGenerateEditButton com "true". O GridView irá agora mostrar um link
Edit (Editar) para cada linha, o qual o usuário poderá clicar para
colocar a linha em modo de edição.
Em seguida, precisamos
configurar o GridView para chamar nosso método de atualização dos dados
(o qual vamos adicionar em nosso arquivo code-behind). Podemos fazer
isso definindo o atributo UpdateMethod com o nome do nosso método, neste
caso "UpdateProduct". A marcação HTML do nosso GridView agora fica
desse jeito:
<asp:GridView ID="productsGrid" runat="server" DataKeyNames="ProductID"
ModelType="ModelBindingPart3.Product"
AllowPaging="true" AllowSorting="true"
AutoGenerateColumns="false" AutoGenerateEditButton="true"
SelectMethod="GetProducts" UpdateMethod="UpdateProduct">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ID" />
<asp:BoundField DataField="ProductName" HeaderText="Name" SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="# in Stock" SortExpression="UnitsInStock" />
</Columns>
</asp:GridView>
Quando executamos a página, podemos clicar em um dos links "Edit" ao lado de um registro para colocá-lo em modo de edição:

Agora
precisamos implementar o método UpdateProduct() em nosso arquivo
code-behind. Há algumas abordagens que podemos usar para realizar esta
tarefa.
Abordagem 1
Nossa primeira abordagem fará
com que o sistema de vinculação de dados do Web Form passe uma instância
de um objeto Product para o nosso método de atualização, o qual podemos
então usar para conectar ao nosso contexto do EF e aplicar seus valores
no banco de dados:
public void UpdateProduct(Product product)
{
// 'product' was implicitly model bound using data-control values
_db.Entry(product).State = System.Data.EntityState.Modified;
_db.SaveChanges();
}
Nosso
método acima usa um único parâmetro do tipo ao qual o GridView está
vinculado - que é o tipo Product. Quando o método UpdateProduct é
chamado pelo sistema do Modelo de Vinculação de Dados, ele irá
implicitamente criar uma instância do objeto Product e tentará vincular
os valores do controle de dados (nosso GridView) aos membros desta
instância do objeto. Nosso método, UpdateProduct então informa ao EF
que o estado do objeto Product foi modificado - o que fará com que o EF
marque esse objeto como alterado, antes de finalmente salvar as
alterações no banco de dados.
Abordagem 2
Embora a
abordagem 1 funcione para casos simples, muitas vezes seu controle de
dados não será capaz de fornecer valores para cada membro do seu objeto,
porque eles não foram exibidos na página ou porque eles representam
relacionamentos com outros objetos. Nesses casos, uma melhor abordagem é
primeiramente carregar o objeto que será atualizado a partir do banco
de dados (usando sua chave primária), e depois explicitamente instruir o
sistema de Vinculação de Dados para que este ligue os valores do controle
de dados nos membros que ele conseguir. Vamos mudar o nosso método de
atualização para usar esta abordagem:
public void UpdateProduct(int productId)
{
var product = _db.Products.Find(productId);
// Explicitly model bind data-control values onto 'product'
TryUpdateModel(product);
_db.SaveChanges();
}
Desta
vez, o sistema de Model Binding do Web Form irá preencher o parâmetro
productId a partir da coleção DataKeys do controle de dados (ele faz
isso implicitamente, nenhum atributo de provedor de valor é necessário).
Em seguida, recuperamos o produto do banco de dados e chamamos o método
TryUpdateModel para fazer a vinculação dos valores do controle de dados
no objeto. Uma vez feito isso, nós salvamos as alterações no banco de
dados.
Validação do Modelo
É claro que a
maioria dos modelos de dados incluem algum tipo de regras de validação.
Para facilitar isso, o sistema de Model Binding dos Web Forms suporta a
validação do modelo utilizando os mesmos atributos de validação do
namespace System.ComponentModel.DataAnnotations que a ASP.NET Dynamic
Data, MVC, Entity Framework e Serviçõs Silverlight RIA utilizam. Você
pode decorar as propriedades em suas classes do modelo com esses
atributos para fornecer informações adicionais sobre a "forma" do seu
modelo, incluindo detalhes sobre quais propriedades exigem um valor e o
intervalo de valores válidos.
Vamos atualizar nossa classe Product com informações de validação correspondentes ao esquema do banco de dados:

Nós podemos fazer isso adicionando os seguintes atributos em nossa classe Product:
public class Product
{
public int ProductID { get; set; }
[Required, StringLength(40)]
public string ProductName { get; set; }
[StringLength(20)]
public string QuantityPerUnit { get; set; }
[DataType(DataType.Currency)]
public decimal? UnitPrice { get; set; }
public short? UnitsInStock { get; set; }
public short? UnitsOnOrder { get; set; }
public short? ReorderLevel { get; set; }
public bool Discontinued { get; set; }
public int? CategoryID { get; set; }
public virtual Category Category { get; set; }
}
Agora,
quando os valores são vinculados a este tipo, o sistema de Model
Binding do Web Form irá monitorar se alguma dessas regras de validação
foram violadas através da propriedade ModelState da página. Podemos,
então, explicitamente inspecionar a propriedade para garantir que o
estado do modelo é válido antes de salvar as alterações:
public void UpdateProduct(int productId)
{
var product = _db.Products.Find(productId);
TryUpdateModel(product);
// Check whether there were any validation errors
if (ModelState.IsValid)
{
_db.SaveChanges();
}
}
Para
exibir esses erros referentes ao estado do modelo na página, podemos
adicionar um controle <asp:ValidationSummary>, com sua propriedade
ShowModelStateErrors setada com true:
<asp:ValidationSummary runat="server" ShowModelStateErrors="true" />
Agora,
se tentarmos atualizar um registro com um valor inválido, o GridView
vai ficar em modo de edição e a mensagem de erro do estado do modelo
será exibida pelo ValidationSummary:

Você
também pode adicionar mensagens de erro personalizadas ou avulsas no
estado do modelo da página, para representar outras condições de erro
não abrangidas pelos atributos de validação. Assim como acontece com os
controladores da ASP.NET MVC, a classe base da Página de um Web Form
tem agora uma propriedade "ModelState" que você pode usar para preencher
mensagens de erro personalizadas, as quais os controles de validação
dentro da página podem acessar e usar para exibir qualquer mensagem de
erro que você quiser.
Vídeo rápido sobre Model Binding e Atualização de Dados
Damian Edwards tem um ótimo video de 90 segundo
(em Inglês) que mostra o uso de Model Binding para implementar cenários de
atualização de dados. Você pode assistir o vídeo de 90 segundos aqui.
Sumário
O
sistema de Model Binding na ASP.NET Web Forms 4.5 facilita o trabalho
com dados e entrada do usuário usando um paradigma de acesso a dados
centrado em código. Ele toma emprestado alguns dos conceitos do modelo
de ligação que introduzimos pela primeira vez com a ASP.NET MVC, e
suporta uma forma consistente de usar os atributos DataAnnotation em
ambos MVC e WebForms para aplicar o comportamento de validação de dados
em objetos de modelo. Todas as técnicas mostradas aqui podem ser
igualmente aplicadas em outros controles de dados da ASP.NET Web Forms,
incluindo FormView, DetailsView e ListView.
Espero que ajude,
Scott
P.S. Além do blog, eu uso o Twitter para disponibilizar posts rápidos e para compartilhar links. Meu apelido no Twitter é: @scottgu
Texto traduzido do post original por
Leniel Macaferi.