Neste artigo vamos iniciar a criação de uma aplicação ASP .NET Core MVC usando o Entity Framework Core no Visual Studio 2017.
Esta série de artigos inicia a criação de uma aplicação ASP .NET Core MVC usando o Entity Framework Core com o Visual Studio 2017, e, esta baseada nos artigos originais publicados em https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro com algumas adaptações, traduções e ajustes.
A aplicação de exemplo criada será o site de uma Universidade fictícia que eu vou chamar de Universidade Macoratti e vai incluir funcionalidades como admissão de alunos, criação de cursos e atribuições de instrutores onde iremos usar a ASP .NET Core 1.1 MVC, o Entity Framework Core 1.1 e o Visual Studio 2017.
Você pode baixar a aplicação original neste link : https://github.com/aspnet/Docs/tree/master/aspnetcore/data/ef-mvc/intro/samples/cu-final
Lembrando que o Entity Framework Core 1.1 é a última versão do EF mas ele não possui todos os recursos do Entity Framework 6.x. (Ele esta disponível via nuget: Install-Package Microsoft.EntityFrameworkCore)
O Entity Framework Core (EF Core) é uma versão leve, extensível e multiplataforma do Entity Framework. O EF Core introduz muitas melhorias e novos recursos quando comparado com o EF6.x. O EF Core mantém a experiência do desenvolvedor do EF6.x e a maioria das APIs de alto nível permanecem as mesmas, então o EF Core vai te parecer muito familiar se você conhece o Entity Framework 6.x.
Ao mesmo tempo, o EF Core é construído sobre um conjunto completamente novo de componentes principais. Isso significa que o EF Core não herda automaticamente todos os recursos do EF6.x. Alguns desses recursos serão exibidos em lançamentos futuros (como o lazy loading e a resiliência de conexão), outros recursos menos usados não serão implementados no EF Core. O núcleo novo, extensível e leve também nos permitiu adicionar alguns recursos ao EF Core que não serão implementados no EF6.x.
Para acompanhar este artigo você precisa ter instalado o Visual Studio Community 2017 com os seguintes workloads (cargas de trabalho) instalados:
Criando o projeto Exemplo : Universidade Macoratti no VS Community 2017
A aplicação exemplo que vamos construir nestes tutoriais é um simples site de uma universidade onde os usuários podem visualizar e atualizar informações de alunos, cursos e instrutores, onde iremos focar na utilização do Entity Framework Core.
Vamos iniciar criando uma aplicação ASP .NET Core MVC Web Application.
Abra no VS community 2017 e no menu File clique em New Project;
A seguir selecione o template Visual C# -> .NET Core e marque ASP .NET Core Web Application (.NET Core);
Dessa forma estamos criando uma aplicação web (MVC com views e controllers) usando o framework .NET Core.
Informe o nome UniversidadeMacoratti (ou outro a seu gosto) e clique no botão OK;
Na próxima janela escolha a versão ASP .NET Core 1.1 e marque o template Web Application sem autenticação e clique no botão OK;
Você terá o seguinte projeto criado:
O Visual Studio utiliza um template padrão para o projeto Web Application que é criado e pode ser visto na figura acima.
Temos assim uma aplicação funcional, na verdade , um simples projeto inicial, que será o nosso ponto de partida.
Pressione F5 para rodar a aplicação no modo debug ou Ctrl+F5 para rodar no modo não debug. (O VS inicia o servidor IIS Express e executa a nossa aplicação.)
Observe que o endereço na barra de navegação exibe localhost:14240/ que indica a porta onde a aplicação esta atendendo.
Ajustando o estilo do site
Vamos fazer alguns ajustes iniciais apenas para alterar o menu do site, o seu leiaute e a página incial.
Para isso vamos abrir o arquivo _Layout.cshtml na pasta /Views/Shared e realizar as seguintes alterações:
- Traduzir os textos para o português quando pertinente;
- Alterar o texto UniversidadeMacoratti para Universidade Macoratti;
- Incluir entradas de menu para as seguintes opções : Estudantes, Cursos, Instrutores e Departamentos;
- Deletar a opção Contato do menu;
Abaixo temos as alterações implementadas no arquivo _Layout.cshtml:
@inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Universidade Macoratti</title> <environment names="Development"> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment> <environment names="Staging,Production"> <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> </environment> @Html.Raw(JavaScriptSnippet.FullScript) </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">Universidade Macoratti</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li> <li><a asp-area="" asp-controller="Home" asp-action="About">Sobre</a></li> <li><a asp-area="" asp-controller="Estudantes" asp-action="Index">Estudantes</a></li> <li><a asp-area="" asp-controller="Cursos" asp-action="Index">Cursos</a></li> <li><a asp-area="" asp-controller="Instrutores" asp-action="Index">Instrutores</a></li> <li><a asp-area="" asp-controller="Departamentos" asp-action="Index">Departamentos</a></li> </ul> </div> </div> </nav> <div class="container body-content"> @RenderBody() <hr /> <footer> <p>© 2017 - Universidade Macoratti</p> </footer> </div> <environment names="Development"> <script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="~/js/site.js" asp-append-version="true"></script> </environment> <environment names="Staging,Production"> <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js" asp-fallback-src="~/lib/jquery/dist/jquery.min.js" asp-fallback-test="window.jQuery" crossorigin="anonymous" integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk"> </script> <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js" asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js" asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal" crossorigin="anonymous" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"> </script> <script src="~/js/site.min.js" asp-append-version="true"></script> </environment> @RenderSection("Scripts", required: false) </body> </html>
A seguir vamos alterar o código da view Index.cshtml na pasta /Views/Home substituindo o texto existente pelo texto exibido a seguir:
@{ ViewData["Title"] = "Home Page"; } <div class="jumbotron"> <h1>Universidade Macoratti</h1> </div> <div class="row"> <div class="col-md-4"> <h2>Bem-Vindo à Universidade Macoratti</h2> <p> Universidade Macoratti é uma aplicação exemplo que demonstra como usar o Entity Framework Core em uma aplicação ASP.NET Core MVC web application. </p> </div> <div class="col-md-4"> <h2>Construindo deste o início</h2> <p>Você pode criar a aplicação seguindo os seguintes passos nesta série de tutoriais.</p> <p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">Veja o tutorial »</a></p> </div> <div class="col-md-4"> <h2>Baixe o projeto completo</h2> <p>Você pode baixar o projeto completo do GitHub.</p> <p><a class="btn btn-default" href="https://github.com/aspnet/Docs/tree/master/aspnet/data/ef-mvc/intro/samples/cu-final">Veja o código fonte do projeto »</a></p> </div> </div>
Após fazer essas alterações executando novamente a aplicação (F5 ou CTRL+F5) teremos o seguinte resultado:
Simplificamos assim o leiaute da aplicação. Vamos agora incluir o suporte ao Entity Framework Core em nossa aplicação.
Adicionando o suporte para o Entity Framework Core via Nuget
Vamos adicionar o suporte ao EF Core em nosso projeto e instalar o provedor do banco de dados que vamos usar. No exemplo deste artigo vamos instalar o provedor SQL Server : Microsoft.EntityFrameworkCore.SqlServer.
Para instalar esse pacote abra uma janela do Package Manager Console via menu Tools e digite o comando : Install-Package Microsoft.EntityFrameworkCore.SqlServer
Este pacote e suas dependências (Microsoft.EntityFrameworkCore e Microsoft.EntityFrameworkCore.Relational) fornece o suporte em tempo de execução ao EF.(Mais adiante iremos instalar outro pacote para a migração)
Nota: O EF para no .NET Core não possui todas as funcionalidades do EF 6. (lazy loading não esta suportado ainda)
Criando o nosso modelo de dados
Agora que temos o suporte ao EF Core vamos criar as classes das entidades para a nossa aplicação. Vamos inciar com as seguintes três entidades :
Neste modelo temos que :
- Existe um relacionamento um-para-muitos entre as entidades Estudante e Matricula
- Existe um relacionamento um-para-muitos entre as entidades Curso e Matricula
Dessa forma um estudante pode estar matriculado em qualquer número de cursos e um curso pode ter qualquer número de estudantes matriculados.
Vamos agora criar classes que representam as nossas entidades.
1- Criando a entidade Estudante
Vamos criar uma pasta chamada “Models” no projeto para nesta pasta definir o modelo de entidades.
Nota: Você pode colocar classes do modelo em qualquer lugar em seu projeto, mas a pasta Models é usada por convenção.
Na janela Solution Explorer, clique com o botão direito do mouse no projeto e selecione Add -> New Folder e informe o nome Models.
As classes são criadas na pasta Models clicando com o botão direito sobre a pasta, selecionando Add -> Class e a seguir informando o nome da classe.
Vamos iniciar criando o arquivo Estudante.cs e nele vamos definir a classe Estudante conforme abaixo:
using System; using System.Collections.Generic; namespace UniversidadeMacoratti.Models { public class Estudante { public int EstudanteID { get; set; } public string SobreNome { get; set; } public string Nome { get; set; } public DateTime DataMatricula { get; set; } public ICollection<Matricula> Matriculas { get; set; } } }
A propriedade EstudanteID será a coluna de chave primária da tabela de banco de dados que corresponde a essa classe. Por padrão, o Entity Framework interpreta uma propriedade que é chamada de ID ou nome_classeID como sendo a chave primária.(Podemos alterar esse comportamento com annotations)
A propriedade de Matricula é uma propriedade de navegação. As propriedades de navegação tratam outras entidades que estão relacionadas com esta entidade permitindo que acessemos propriedades relacionadas.
Neste caso, a propriedade Matriculas da entidade Estudante irá tratar todas as entidades Matricula que estão relacionadas com essa entidade Estudante. Ou seja , se um registro de estudante na base de dados possuir dois registros matricula relacionados, a propriedades de navegação Matriculas da entidade Estudante irá conter as duas entidades Matricula.
Se uma propriedade de navegação pode conter várias entidades (como nas relações many-to-many ou one-to-many), seu tipo deve ser uma lista na qual as entradas podem ser adicionadas, excluídas e atualizadas, como ICollection<T>. Você pode especificar ICollection<T> ou um tipo como uma List<T> ou HashSet<T>. Se você especificar ICollection<T>, o EF cria uma coleção HashSet<T> por padrão.
2- Criando a entidade Matricula
Na mesma pasta Models vamos criar a classe Matricula.cs e definir o código da classe Matricula conforme abaixo:
namespace UniversidadeMacoratti.Models { public enum Nota { A, B, C, D, F } public class Matricula { public int MatriculaID { get; set; } public int CursoID { get; set; } public int EstudanteID { get; set; } public Nota? Nota { get; set; } public Curso Curso { get; set; } public Estudante Estudante { get; set; } } }
A propriedade MatriculaID será a chave primária; Essa entidade usa o padrão classnameID em vez de ID por si mesmo como fizemos na entidade Estudante. É bom você escolher um padrão e usar esse padrão em todo o seu modelo de dados. Aqui, a variação ilustra que você pode usar qualquer padrão. Em um tutorial posterior, você verá como o uso de ID sem classname torna mais fácil implementar a herança no modelo de dados.
A propriedade Nota um enum. O ponto de interrogação após a declaração de tipo Nota indica que a propriedade Nota é anulável. Uma nota que é nula é diferente de uma nota zero – nula significa que uma nota não é conhecida ou ainda não foi atribuída.
A propriedade EstudanteID é uma chave estrangeira e a propriedade de navegação correspondente é Estudante. Uma entidade Matricula está associada a uma entidade Estudante, de modo que a propriedade só pode conter uma única entidade Estudante (ao contrário da propriedade de navegação Estudante.Matriculas que você viu anteriormente, que pode conter várias entidades Matricula.
A propriedade CursoID é uma chave estrangeira e a propriedade de navegação correspondente é Curso. Uma entidade Matricula está associada a uma entidade Curso.
O Entity Framework interpreta uma propriedade como uma propriedade de chave estrangeira se ela for nomeada assim : <nome da propriedade de navegação><nome da propriedade da chave primária> (Ex: EstudanteID para a propriedade de navegação do Estudante, uma vez que a chave primária da entidade Estudante é ID).
As propriedades de chave estrangeira também podem ser nomeadas simplesmente assim: <nome da propriedade da chave primária> (Ex: CursoID, uma vez que a chave principal da Curso é CursoID).
3- Criando a entidade Curso
Na mesma pasta Models vamos criar a classe Curso.cs e definir o código da classe Curso conforme abaixo:
using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; namespace UniversidadeMacoratti.Models { public class Curso { [DatabaseGenerated(DatabaseGeneratedOption.None)] public int CursoID { get; set; } public string Titulo { get; set; } public int Creditos { get; set; } public ICollection<Matricula> Matriculas { get; set; } } }
O atributo [DatabaseGenerated] é usado em campos computados e quando definido com a opção DatabaseGeneratedOption.None faz com que o banco de dados não gere um valor para a propriedade quando linhas forem inseridas ou atualizadas na respectiva tabela.
No caso ela esta sendo usada para que a propriedade CursoID não seja definida como um campo Identity pelo SQL Server.
Estamos usando a abordagem Code-First do Entity Framework e nesta abordagem escrevemos as nossas classes POCO em primeiro lugar e, em seguida, o EF cria o banco de dados a partir dessas classes POCO (Plain Old CLR Objects).
Dessa forma, quando decidimos usar o Code-First não precisamos começar nossa aplicação criando o banco de dados ou definindo um esquema mas podemos iniciar escrevendo classes .NET para definir o modelo de objetos do nosso domínio sem ter que misturar a lógica de persistência de dados com as classes.
Nota : O Entity Framework por padrão adota algumas convenções (Conventions) que ele usa para realizar algumas operações.
Dessa forma temos o nosso modelo de entidades pronto e vamos continuar a próxima parte do artigo criando o contexto do banco de dados e definindo os dados de testes que iremos usar.