ASP .NET - MVC Music Store - Definindo o Model e o Acesso aos Dados


Até agora, estamos passando "dados fictícios" dos nossos controladores para as nossas View; vamos melhorar isso.

Agora estamos prontos para usar um banco de dados real. Neste tutorial vamos ver como usar o SQL Server Compact Edition (muitas vezes chamado de SQL CE) como nosso motor de banco de dados. O SQL CE é um banco de dados livre, embutido e baseado em arquivos que não requer qualquer tipo de instalação ou configuração, o que o torna muito conveniente para o desenvolvimento local.

O acesso aos dados com Entity Framework Code First

Nós vamos usar o Entity Framework(EF) que está incluído no ASP.NET MVC 3 para consultar e atualizar o banco de dados. O EF é uma ferramenta ORM flexível usada para realizar o mapeamento objeto relacional que permite aos desenvolvedores consultar e atualizar dados armazenados em um banco de dados de uma forma orientada a objetos.

A versão atual do Entity Framework é a versão 5 que suporta um paradigma de desenvolvimento chamado Code-First. O Code-First permite criar o modelo de objetos, escrevendo classes simples (também conhecido como classes POCO ou seja objetos CLR), e pode criar o banco de dados em tempo real a partir de suas classes.

Vamos aproveitar o recurso de criação de banco de dados no Entity Framework neste tutorial. Antes de fazer isso, porém, vamos fazer algumas pequenas mudanças em nossas classes do modelo.

Em nossa loja um Album estará associado com Artistas, por isso vamos adicionar uma classe modelo simples para descrever um artista. Adicione uma nova classe chamada Artista.vb na pasta Models usando o código mostrado a seguir:

A seguir vamos atualizar a nossa classe Album incluindo mais algumas propriedades conforme o código abaixo:

Continuando as alterações vamos alterar agora a classe Genero conforme código descrito a seguir:

Usando a pasta App_Data e definindo a string de conexão

Vamos usar o diretório App_Data do nosso projeto para manter os nossos arquivos de banco de dados SQL Server Express. A pasta App_Data é um diretório especial no ASP.NET que já tem as permissões de segurança corretas de acesso a banco de dados. (Se fosse preciso criar a pasta App_Data teríamos que acessar o menu Project selecionar Add ASP .NET Folder informando o nome da pasta)

Vamos alterar o arquivo de configuração do site chamado Web.Config de maneira que o Entity Framework saiba como se conectar com o nosso banco de dados.

Clique duas vezes sobre o arquivo Web.Config na raiz do projeto e no final do arquivo inclua uma seção <connectionStrings> conforme o código a seguir:

Agora vamos criar uma classe de contexto na pasta Models. Clique com o botão direito sobre a pasta Models e selecione Add Class;

A seguir selecione o template Class e informe o nome MusicStoreEntities.vb e defina o código da classe conforme mostra a figura abaixo:

E isso é tudo que precisamos. Apenas definimos as classes POCO para representar nossas entidades, o arquivo de contexto e a string de conexão com o banco de dados. A partir dessas informações o Entity Framework irá criar o banco de dados e as tabelas.

Ao estender a classe base DbContext nossa classe MusicStoreEntities estará apta a tratar as operações com nosso banco de dados. Vamos agora incluir algumas propriedades em nosso modelo de classes.

Vamos tirar proveito de um recurso no Entity Framework que acrescenta uma "semente"(seed) de dados a um banco de dados recém-criado. Isto irá pré-preencher o nosso catálogo de loja com uma lista de gêneros, artistas e álbuns. O arquivo com dados chama-se SampleData.vb e deve ser copiado para a pasta Models.

Agora precisamos adicionar uma linha de código para dizer ao Entity Framework sobre essa classe SampleData. Dê um duplo clique no arquivo Global.asax na raiz do projeto para abri-lo e adicione a seguinte linha de código na parte superior do método Application_Start.

E com isso concluímos o trabalho necessário para configurar o Entity Framework para o nosso projeto.

Baixe os arquivos da pasta Models, Views, Controllers e ViewModel aqui : MvcMusicStore_Arquivos.zip

Consultando o banco de dados

Agora vamos atualizar nossa classe StoreController de modo que em vez de usar "dados fictícios", possamos consultar o nosso banco de dados. Vamos começar por declarar um campo no StoreController para manter uma instância da classe MusicStoreEntities, chamada storeDB:

Dim storeDB As New MusicStoreEntities()

A classe MusicStoreEntities é mantida pelo Entity Framework e expõe uma coleção de propriedades para cada tabela em nosso banco de dados. Vamos atualizar o controlador StoreController para retornar todos os gêneros no banco de dados:

Public Function Index() As ActionResult
   Dim storeDB As New MusicStoreEntities()
   Dim generos = storeDB.Generos.ToList()
   Return View(generos)
End Function

Não precisamos alterar nada na nossa View Index no controle StoreController pois ela ainda esta retornando o mesmo ViewModel que antes, a única diferença é que agora estamos retornando os dados a partir do nosso banco de dados que será criado via Code First na pasta App_Data.

Execute o projeto e navegue até a URL /Store para ver a lista de todos os gêneros no banco de dados:

Se você espiar a pasta App_Data irá ver que o banco de dados MvcMusicStore.sdf foi criado nesta pasta;

Abrindo o banco de dados iremos ver as tabelas : Albums, Artistas e Generoes que foram criadas bem com as respectivas colunas.

Obs: Por padrão o EF utiliza a regra da língua inglesa para pluralizar o nome da tabela a partir da entidade. Por isso a classe Genero foi mapeada para a tabela Generoes.

Tudo isso graças ao Entity Framework e o mapeamento relacional feito a partir das classes POCO definidas.

Atualizando as view Procurar e Detalhes

Com o método Action /Store/Procurar?genero=[genero], estamos procurando um gênero pelo nome.

Com isso estamos esperando um único resultado, já que não deve existir duas entradas para mesmo gênero por isso podemos usar o método de extensão .Single() na consulta LINQ para o objeto Genero apropriado como no exemplo a seguir:

Dim exemplo = storeDB.Generos.[Single](Function(g) g.Nome = 'Disco')

O método Single usa uma expressão lambda como um parâmetro, que especifica que queremos um objeto único gênero de tal forma que seu nome corresponde ao valor que você definiu. No caso igual a "Disco".

Vamos tirar proveito de uma característica do Entity Framework que permite a indicação de outras entidades relacionadas que queremos carregar bem como quando o objeto Genero for recuperado.

Este recurso é chamado de Query Result Shaping - Resultado da Consulta Shaping - e nos permite reduzir o número de vezes que precisam acessar o banco de dados para recuperar todas as informações que precisamos. Queremos pré-selecionar os Álbuns para o gênero retornado, então vamos atualizar nossa consulta para incluir Generos.Include("Albuns") para indicar que queremos álbuns relacionados também. Isso é mais eficiente, uma vez que irá recuperar tantos dados do gênero como dos álbuns em uma única requisição ao banco de dados.

Abaixo temos a nossa Action Procurar do controlador StoreController atualizada:

        ' GET: /Store/Procurar
        Public Function Procurar(genero As String) As ActionResult
            Dim generoModel = storeDB.Generos.Include("Albuns").Single(Function(g) g.Nome = genero)
            Return View(generoModel)
        End Function 

Podemos atualizar agora a View Procurar para mostrar os álbuns que estão disponíveis em cada gênero. Abra o template View encontrado em /Views/Store/Procurar.vbhtml e adicione uma lista com marcadores de álbuns como mostrado abaixo.

Executando o nosso aplicativo e navegando para /Store/Procurar?genero='Jazz'(clique em qualquer gênero) teremos que como resultado todos os álbuns para o gênero selecionado obtidos a partir do banco de dados:

Vamos agora alterar nossa Action Detalhes para obter os detalhes de um álbum.

Vamos realizar uma consulta LINQ usando o método Find para procurar os detalhes de um álbum pelo seu id.

Altere a Action Detalhes do controlador StoreController conforme o código a seguir:

 ' GET: /Store/Detalhes
        Public Function Detalhes(id As Integer) As ActionResult
            Dim album = storeDB.Albuns.Find(id)
            Return View(album)
        End Function

Executando novamente nossa aplicação e navegando para /Store/Detalhes/1 teremos a exibição dos resultados obtidos do banco de dados conforme a figura abaixo:

Agora que a nossa página de detalhes esta configurada para exibir um álbum pelo seu ID , vamos atualizar a view Procurar para vincular com a view Detalhes.

Vamos usar o método Html.ActionLink, exatamente como fizemos para vincular a view Index com a Action Procurar no final da seção anterior. O código alterado é mostrado abaixo:

@ModelType MvcMusicStore.Genero

@Code
    ViewBag.Title = "Procurar"
End Code

<h2>Procurando Gênero: @Model.Nome</h2>
<ul>
     @For Each album In Model.Albuns
       @<li>
           @Html.ActionLink(album.Titulo, "Detalhes", New With {.id = album.AlbumId })
       </li>
     Next
</ul>
No método ActionLink(), que é um método Helper, estou exibindo o títuo dos álbuns e criando um link dinâmico que
irá exibir a relação de Álbuns relacionada usando os parâmetros da seguinte forma:
  1. O primeiro parâmetro - O texto do link - album.Titulo
  2. O segundo parâmetro - O nome do método Action - "Detalhes"
  3. O terceiro parâmetro - o id do álbum- "New With {.id = album.AlbumId }"

Nota: O segundo parâmetro pode ser um tipo anônimo.

O método ActionLInk() é baseado no mecanismo de rotas do ASP .NET MVC e nas regras definidas no Global.asax ,
seção Application_Start.

Agora já temos condições para navegar para nossa página de loja(/Store), para uma página de gênero, que lista os álbuns disponíveis e, ao clicar em um álbum, podemos ver os detalhes para esse álbum:

No próximo tutorial vamos tratar da edição dos dados: ASP .NET - MVC Music Store - Editando dados

Referências:


José Carlos Macoratti