A importância e o uso do Data Annotation

Por Renato Haddad

Maio, 2012

JJ129537.060DE5057573180CEC6D227C6D3E2207(pt-br,MSDN.10).png

O uso do Data Annotation se tornou uma realidade em praticamente todos os tipos de aplicações em .NET, e sendo assim, é importante o desenvolvedor aprender como usá-lo, a finalidade, os atributos e o uso em si.

No VS.NET 2010 crie um projeto do tipo ASP.NET MVC 3 com o template de Internet Application, conforme figura a seguir.

JJ129537.B6D43C8CD5F4E94D7074E36BFC7E468A(pt-br,MSDN.10).png

Já que é um modelo de MVC e o Model representa o modelo de entidades/objeto, na pasta Model, o primeiro passo é criar a classe a ser usada. Neste caso, vamos criar uma classe chamada Produto.cs contento das seguintes propriedades.

public class Produto
{
    public int ID { get; set; }
    public string Nome { get; set; }
    public double Qtde { get; set; }
    public decimal Preco { get; set; }
    public DateTime Dt_Vencto { get; set; }
}

Como esta classe representará o cadastro de produtos, então abra o arquivo Web.Config e atribua os dados referentes ao banco de dados em si. Neste caso, a chave (name) será ConnDB que aponta para o banco Artigo.sdf que é do SQL Server 4.0. Você estar pensando onde está o banco? Até agora não existe nenhum banco de dados, pois usarei o conceito de Code First com o POCO (Plain Old CLR Object) para criar primeiro a classe e depois o banco na hora de executar a aplicação.

<connectionStrings>
  <add name="ConnDB"
        connectionString="Data Source=|DataDirectory|Artigo.sdf"
        providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>

Em seguida vamos criar a lógica do negócio, e no modelo MVC o correto é criar o Controller, o qual irá conter todos os métodos do CRUD para manutenção de dados. Para isto, é necessário compilar o projeto, pressione F6 e veja se foi compilado com sucesso.

Na pasta Controller, clique com o botão direito e selecione Add Controller. O nome será ProdutoController, o Template será “Controller with read/write actions and views, using Entity Framework”, conforme figura a seguir. Com isto serão gerados todos os métodos do CRUD baseado no EF. Em Model class, selecione Produto, daí a necessidade de se compilar o projeto antes.

JJ129537.75C7F930603A10499083C79A51EFB4EF(pt-br,MSDN.10).png

Agora vem um passo importante que é o “Data contexto class”. Selecione “New Data Context” e digite o nome DBContext. O contexto é a classe que irá gerenciar todo o contexto.

JJ129537.74BF802532BB4ECD2ACE26260DDDC240(pt-br,MSDN.10).png

Agora sim, pode clicar no botão OK. Na opção Views, deixe o Razor (CSHTML) para que as páginas sejam criadas com o Razor. Clique no botão Add e note que serão criadas as classes DBContext.cs, a ProdutoController.cs assim como uma pasta chamada Produto dentro da pasta Views.

Primeiramente abra o arquivo DBContext.cs e note que foi criada uma propriedade do tipo DbSet<Produto> chamada Produtoes. Este nome Produtoes está no plural em inglês. Sei que isto está errado, mas o VS gera assim devido um termo chamado pluralization. Não vou explanar sobre isto porque foge do foco do artigo, mas o mais fácil é renomear para Produtos. Como esta classe é referenciada em outros locais, exatamente sobre Produtos renomeado, dê um CTRL + . (ponto) e ENTER para replicar a renomeação em todo o projeto.

Observe ainda que a classe DBContext herda de DbContext.

public class DBContext : DbContext
{
    public DbSet<Produto> Produtoes { get; set; }
}

Crie um construtor para a classe DBContext de forma que seja herdado da classe base onde o nome da chave do banco de dados a ser gerado é exatamente a definida no Web.Config anteriormente. Neste caso é ConnDB.

public DBContext(): base("ConnDB"){}

Agora abra a classe ProdutoController e veja que o VS gerou absolutamente todos os métodos necessários para qualquer manutenção de dados. Observe que esta classe herda de Controller e logo em seguida há a referência do DBContext.

public class ProdutoController : Controller
{
    private DBContext db = new DBContext();

    //
    // GET: /Produto/

    public ViewResult Index()
    {
        return View(db.Produtos.ToList());
    }

    //
    // GET: /Produto/Details/5

    public ViewResult Details(int id)
    {
        Produto produto = db.Produtos.Find(id);
        return View(produto);
    }

    //
    // GET: /Produto/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Produto/Create

    [HttpPost]
    public ActionResult Create(Produto produto)
    {
        if (ModelState.IsValid)
        {
            db.Produtos.Add(produto);
            db.SaveChanges();
            return RedirectToAction("Index");  
        }

        return View(produto);
    }
        
    //
    // GET: /Produto/Edit/5
 
    public ActionResult Edit(int id)
    {
        Produto produto = db.Produtos.Find(id);
        return View(produto);
    }

    //
    // POST: /Produto/Edit/5

    [HttpPost]
    public ActionResult Edit(Produto produto)
    {
        if (ModelState.IsValid)
        {
            db.Entry(produto).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(produto);
    }

    //
    // GET: /Produto/Delete/5
 
    public ActionResult Delete(int id)
    {
        Produto produto = db.Produtos.Find(id);
        return View(produto);
    }

    //
    // POST: /Produto/Delete/5

    [HttpPost, ActionName("Delete")]
    public ActionResult DeleteConfirmed(int id)
    {            
        Produto produto = db.Produtos.Find(id);
        db.Produtos.Remove(produto);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}

Pronto, o projeto está feito para execução. Pressione F5 para abrir no browser e na URL coloque http://localhost:1876/Produto, sendo que o 1876 é aleatório. Veja que é aberta a janela de produto sem nenhum produto.

JJ129537.3DE5A3576F8D2663CB182B06F96DE04B(pt-br,MSDN.10).png

Clique em Create New para abrir o formulário de cadastro. Digite os dados e clique em Create.

JJ129537.06C2173B611ADE554F5F92282226CD07(pt-br,MSDN.10).png

Veja na tela principal de produto, este já é mostrado com o produto cadastrado.

JJ129537.26B1B4EEE1B2ED6A76E60D625A45F714(pt-br,MSDN.10).png

Data Annotation

Agora vem o principal item deste artigo. Nas telas de produto os nomes dos campos mostrados são os nomes das propriedades da classe Produto. No entanto, em qualquer tela do CRUD eu posso digitar qualquer valor do respectivo tipo, assim como não há nenhuma crítica de campos obrigatórios, validação de valores digitados, formato da data apresentada, etc. Aqui é que entra o Data Annotation.

Abra a classe Produto, na lista de using coloque:

using System.ComponentModel.DataAnnotations;

Adicione os atributos do Data Annotation para cada propriedade de acordo com a seguinte listagem:
public class Produto
{
    [Key]
    [Column(Order = 0)]
    public int ID { get; set; }

    [Required(ErrorMessage = "Digite o nome do produto."), Column(Order = 1)]
    [MinLength(5, ErrorMessage = "O tamanho mínimo do nome são 5 caracteres.")]
    [StringLength(200, ErrorMessage = "O tamanho máximo são 200 caracteres.")]
    public string Nome { get; set; }

    [Display(Name="Quantidade")]
    [DisplayFormat(DataFormatString = "{0:n2}",
            ApplyFormatInEditMode = true,
            NullDisplayText = "Estoque vazio")]
    [Range(10, 25, ErrorMessage = "A Qtde deverá ser entre 10 e 25.")]
    [Column(Order = 2)]
    public double Qtde { get; set; }

    [DisplayFormat(DataFormatString = "{0:n2}",
            ApplyFormatInEditMode = true,
            NullDisplayText = "Sem preço")]
    [Range(3, 500, ErrorMessage = "O preço deverá ser entre 3 e 500.")]
    [Column(Order = 3)]
    public decimal Preco { get; set; }

    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
    [Column(Order = 4)]
    [Display(Name="Vencimento")]
    public DateTime Dt_Vencto { get; set; }
}

Como você pode notar na listagem usei diversos atributos para definir as características e o comportamento das propriedades. Veja a explicação de cada atributo usado:

Key – define que tal propriedade é a chave primária.

Column – é o número da ordem em que a propriedade será criada fisicamente no banco de dados.

Required – significa campo obrigatório, ou seja, caso o internauta não digitar, será mostrada a mensagem definida em ErrorMessage. Desta forma, quando o banco de dados for gerado, a propriedade Allow Null será falso.

MinLength – informa qual é o tamanho mínimo do respectivo campo. Caso a regra seja violada, será exibida a mensagem no ErrorMessage.

StringLength – é o tamanho máximo do campo, inclusive o número atribuído será o MaxLength do campo no banco de dados.

Display – é o nome a ser mostrado em todas as interfaces de usuário. Nem sempre o nome da propriedade é o melhor texto a ser mostrado na UI, portanto, você pode alterar.

DisplayFormat – é o formato a ser exibido na UI. O ApplyFormatInEditMode indica se o formato deverá ser usado quando entrar no modo de edição. O NullDisplayText indica qual é o texto a ser mostrado quando o campo for nulo.

Range – define a faixa de dados aceita pela propriedade. Caso esteja fora da faixa é mostrado o ErrorMessage.

Basicamente estes são os atributos mais usados no Data Annotation. Você pode pesquisar outros atributos na Library da Microsoft.

Uma vez definidos os atributos da classe, pressione F5 para executar a aplicação. Navegue até a página de produtos http://localhost:1876/Produto e veja que será gerado um erro porque houve uma alteração na estrutura da classe. O próprio Entity Framework identifica isto. Então é preciso realizar uma alteração no arquivo Global.asax.cs. Adicione os seguintes using:

using System.Data.Entity;
using MvcApp_MSDN.Models;

Localize o método a seguir e adicione a linha do Database.SetInitializer o qual identifica se houve alguma alteração na estrutura do banco desde a última execução. Caso haja, ele recria o banco de dados e você perde os existentes. Não se preocupe que há o Migrations no .NET para evitar perder os dados, mas não é o foco deste artigo.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    Database.SetInitializer(new DropCreateDatabaseIfModelChanges<DBContext>());            
}

Agora sim, pode executar o projeto e adicionar vários produtos. Veja que sensacional a tela de entrada de dados contendo todas as críticas que impusemos. Perceba que é automático, basta definir os atributos do Data Annotations nas propriedades das classes e pronto.

JJ129537.57361BFAF3C2FAFEE808168D9865F830(pt-br,MSDN.10).png

Conclusão

Dedique um tempo aos estudos do Data Annotations porque muitas aplicações estão usando isto, e uma vez aprendido em uma, serve para todas. Cabe dizer que há outras maneiras de implementar os atributos com o Entity Framework 4.1 e 4.3, mas por enquanto é o suficiente. Bons estudos!

Mostrar: