Parte 4: Modelos e Acesso a Dados

por Jon Galloway

O MVC Music Store é um aplicativo de tutorial que apresenta e explica passo a passo como usar ASP.NET MVC e Visual Studio para desenvolvimento na Web.

A MVC Music Store é uma implementação leve de loja de exemplo que vende álbuns de música online e implementa a administração básica do site, a entrada do usuário e a funcionalidade do carrinho de compras.

Esta série de tutoriais detalha todas as etapas executadas para criar o aplicativo de exemplo ASP.NET MVC Music Store. A parte 4 abrange modelos e acesso a dados.

Até agora, acabamos de passar "dados fictícios" de nossos Controladores para nossos modelos de exibição. Agora estamos prontos para conectar um banco de dados real. Neste tutorial, abordaremos como usar o SQL Server Compact Edition (geralmente chamado de SQL CE) como nosso mecanismo de banco de dados. O SQL CE é um banco de dados baseado em arquivo gratuito, inserido e que não requer nenhuma instalação ou configuração, o que o torna realmente conveniente para o desenvolvimento local.

Acesso ao banco de dados com o Entity Framework Code-First

Usaremos o suporte do EF (Entity Framework) incluído em projetos ASP.NET MVC 3 para consultar e atualizar o banco de dados. O EF é uma API de dados ORM (mapeamento relacional de objeto) flexível que permite aos desenvolvedores consultar e atualizar dados armazenados em um banco de dados de maneira orientada a objetos.

O Entity Framework versão 4 dá suporte a um paradigma de desenvolvimento chamado code-first. O code-first permite que você crie um objeto de modelo escrevendo classes simples (também conhecidas como POCO de objetos CLR "simples") e pode até mesmo criar o banco de dados em tempo real a partir de suas classes.

Alterações em nossas classes de modelo

Aproveitaremos o recurso de criação de banco de dados no Entity Framework neste tutorial. Antes de fazermos isso, porém, vamos fazer algumas pequenas alterações em nossas classes de modelo para adicionar algumas coisas que usaremos posteriormente.

Adicionando as classes de modelo de artista

Nossos Álbuns serão associados a Artistas, então adicionaremos uma classe de modelo simples para descrever um artista. Adicione uma nova classe à pasta Models chamada Artist.cs usando o código mostrado abaixo.

namespace MvcMusicStore.Models
{
    public class Artist
    {
        public int ArtistId { get; set; }
        public string Name { get; set; }
    }
}

Atualizando nossas classes de modelo

Atualize a classe Álbum, conforme mostrado abaixo.

namespace MvcMusicStore.Models
{
    public class Album
    {
        public int      AlbumId     { get; set; }
        public int      GenreId     { get; set; }
        public int      ArtistId    { get; set; }
        public string   Title       { get; set; }
        public decimal  Price       { get; set; }
        public string   AlbumArtUrl { get; set; }
        public Genre    Genre       { get; set; }
        public Artist   Artist      { get; set; }
    }
}

Em seguida, faça as seguintes atualizações para a classe Gênero.

using System.Collections.Generic;
 
namespace MvcMusicStore.Models
{
    public partial class Genre
    {
        public int      GenreId     { get; set; }
        public string   Name        { get; set; }
        public string   Description { get; set; }
        public List<Album> Albums   { get; set; }
    }
}

Adicionando a pasta App_Data

Adicionaremos um diretório App_Data ao nosso projeto para manter nossos arquivos de banco de dados SQL Server Express. App_Data é um diretório especial no ASP.NET que já tem as permissões de acesso de segurança corretas para acesso ao banco de dados. No menu Projeto, selecione Adicionar ASP.NET Pasta e App_Data.

Captura de tela do menu Projeto para adicionar o A SP . Pasta N E T para selecionar os Dados do Aplicativo.

Criando uma cadeia de conexão no arquivo web.config

Adicionaremos algumas linhas ao arquivo de configuração do site para que o Entity Framework saiba como se conectar ao nosso banco de dados. Clique duas vezes no arquivo Web.config localizado na raiz do projeto.

Captura de tela do arquivo de configuração da Web no Gerenciador de Soluções para criar uma cadeia de conexão nele.

Role até a parte inferior deste arquivo e adicione uma <seção connectionStrings> diretamente acima da última linha, conforme mostrado abaixo.

<connectionStrings>
    <add name="MusicStoreEntities"
     connectionString="Data Source=|DataDirectory|MvcMusicStore.sdf"
     providerName="System.Data.SqlServerCe.4.0"/>
  </connectionStrings>  
</configuration>

Adicionando uma classe de contexto

Clique com o botão direito do mouse na pasta Modelos e adicione uma nova classe chamada MusicStoreEntities.cs.

Captura de tela da pasta Modelos para adicionar uma Classe de Contexto.

Essa classe representará o contexto do banco de dados do Entity Framework e manipulará nossas operações de criação, leitura, atualização e exclusão para nós. O código para essa classe é mostrado abaixo.

using System.Data.Entity;
 
namespace MvcMusicStore.Models
{
    public class MusicStoreEntities : DbContext
    {
        public DbSet<Album> Albums { get; set; }
        public DbSet<Genre> Genres { get; set; }
    }
}

É isso : não há nenhuma outra configuração, interfaces especiais etc. Ao estender a classe base DbContext, nossa classe MusicStoreEntities é capaz de lidar com nossas operações de banco de dados para nós. Agora que temos essa conexão, vamos adicionar mais algumas propriedades às nossas classes de modelo para aproveitar algumas das informações adicionais em nosso banco de dados.

Adicionando nossos dados do catálogo de repositórios

Aproveitaremos um recurso no Entity Framework que adiciona dados de "semente" a um banco de dados recém-criado. Isso preencherá previamente nosso catálogo de lojas com uma lista de Gêneros, Artistas e Álbuns. O download do MvcMusicStore-Assets.zip - que incluiu nossos arquivos de design de site usados anteriormente neste tutorial - tem um arquivo de classe com esses dados de semente, localizados em uma pasta chamada Code.

Na pasta Código/Modelos, localize o arquivo SampleData.cs e solte-o na pasta Modelos em nosso projeto, conforme mostrado abaixo.

Captura de tela da pasta Código ou Modelos para localizar o arquivo CS de Dados de Exemplo e adicionar os dados do catálogo do repositório.

Agora, precisamos adicionar uma linha de código para informar o Entity Framework sobre essa classe SampleData. Clique duas vezes no arquivo Global.asax na raiz do projeto para abri-lo e adicione a linha a seguir à parte superior do método Application_Start.

protected void Application_Start()
{
    System.Data.Entity.Database.SetInitializer(
    new MvcMusicStore.Models.SampleData());
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
 }

Neste ponto, concluímos o trabalho necessário para configurar o Entity Framework para nosso projeto.

Consultando o banco de dados

Agora, vamos atualizar nosso StoreController para que, em vez de usar "dados fictícios", ele chame nosso banco de dados para consultar todas as informações. Começaremos declarando um campo no StoreController para manter uma instância da classe MusicStoreEntities, chamada storeDB:

public class StoreController : Controller
{
    MusicStoreEntities storeDB = new MusicStoreEntities();

Atualizando o Índice de Repositório para consultar o banco de dados

A classe MusicStoreEntities é mantida pelo Entity Framework e expõe uma propriedade de coleção para cada tabela em nosso banco de dados. Vamos atualizar nossa ação índice StoreController para recuperar todos os Gêneros em nosso banco de dados. Anteriormente, fizemos isso codificando dados de cadeia de caracteres. Agora, podemos usar apenas a coleção Generes de contexto do Entity Framework:

public ActionResult Index()
{
    var genres = storeDB.Genres.ToList();
    return View(genres);
 }

Nenhuma alteração precisa acontecer com nosso modelo de exibição, pois ainda estamos retornando o mesmo StoreIndexViewModel que retornamos antes – estamos apenas retornando dados dinâmicos do nosso banco de dados agora.

Quando executarmos o projeto novamente e visitarmos a URL "/Store", agora veremos uma lista de todos os Gêneros em nosso banco de dados:

Captura de tela da lista de todos os Gêneros no banco de dados.

Atualizando a Navegação no Repositório e detalhes para usar dados dinâmicos

Com o método de ação /Store/Browse?genre=[some-genre] , estamos procurando um Gênero por nome. Esperamos apenas um resultado, já que nunca devemos ter duas entradas para o mesmo nome de gênero e, portanto, podemos usar o . Extensão single() no LINQ para consultar o objeto Genre apropriado como este (não digite isso ainda):

var example = storeDB.Genres.Single(g => g.Name == "Disco");

O método Single usa uma expressão Lambda como um parâmetro, que especifica que queremos um único objeto Genre de modo que seu nome corresponda ao valor que definimos. No caso acima, estamos carregando um único objeto Genre com um valor Name correspondente a Disco.

Aproveitaremos um recurso do Entity Framework que nos permite indicar outras entidades relacionadas que desejamos carregar também quando o objeto Genre for recuperado. Esse recurso é chamado de Formatação de Resultados de Consulta e nos permite reduzir o número de vezes que precisamos para acessar o banco de dados para recuperar todas as informações de que precisamos. Queremos pré-buscar os Álbuns para Gênero que recuperamos, portanto, atualizaremos nossa consulta para incluir de Genres.Include("Albums") para indicar que também queremos álbuns relacionados. Isso é mais eficiente, pois recuperará nossos dados de Gênero e Álbum em uma única solicitação de banco de dados.

Com as explicações fora do caminho, veja a aparência da nossa ação do controlador Browse atualizada:

public ActionResult Browse(string genre)
{
    // Retrieve Genre and its Associated Albums from database
    var genreModel = storeDB.Genres.Include("Albums")
        .Single(g => g.Name == genre);

    return View(genreModel);
}

Agora podemos atualizar o Modo de Exibição de Navegação na Loja para exibir os álbuns que estão disponíveis em cada Gênero. Abra o modelo de exibição (encontrado em /Views/Store/Browse.cshtml) e adicione uma lista com marcadores de Álbuns, conforme mostrado abaixo.

@model MvcMusicStore.Models.Genre
@{
    ViewBag.Title = "Browse";
}
<h2>Browsing Genre: @Model.Name</h2>
<ul>
    @foreach (var album in Model.Albums)
    {
        <li>
            @album.Title
        </li>
    }
</ul>

Executar nosso aplicativo e navegar até /Store/Browse?genre=Jazz mostra que nossos resultados agora estão sendo extraídos do banco de dados, exibindo todos os álbuns em nosso Gênero selecionado.

Captura de tela dos resultados quando extraídos do banco de dados exibe todos os álbuns no Gênero selecionado.

Faremos a mesma alteração em nossa URL /Store/Details/[id] e substituiremos nossos dados fictícios por uma consulta de banco de dados que carrega um Álbum cuja ID corresponde ao valor do parâmetro.

public ActionResult Details(int id)
{
    var album = storeDB.Albums.Find(id);
 
    return View(album);
}

Executar nosso aplicativo e navegar até /Store/Details/1 mostra que nossos resultados agora estão sendo extraídos do banco de dados.

Captura de tela da página Detalhes da Loja mostra que os resultados também estão sendo extraídos do banco de dados.

Agora que nossa página Detalhes da Loja está configurada para exibir um álbum pela ID do Álbum, vamos atualizar o modo de exibição Procurar para vincular à exibição Detalhes. Usaremos Html.ActionLink exatamente como fizemos para vincular do Índice da Loja ao Store Browse no final da seção anterior. A origem completa do modo de exibição Procurar é exibida abaixo.

@model MvcMusicStore.Models.Genre
@{
    ViewBag.Title = "Browse";
}
<h2>Browsing Genre: @Model.Name</h2>
<ul>
    @foreach (var album in Model.Albums)
    {
        <li>
            @Html.ActionLink(album.Title,
"Details", new { id = album.AlbumId })
        </li>
    }
</ul>

Agora podemos navegar de nossa página da Store para uma página Gênero, que lista os álbuns disponíveis e clicando em um álbum, podemos exibir detalhes desse álbum.

Captura de tela da capacidade de navegar da página da Loja para uma página Gênero.