![]()  | 
    
     Neste artigo eu vamos iniciar a criação de uma aplicação ASP .NET Core MVC usando o Entity Framework Core no Visual Studio 2017.  | 
    
				
				![]()  | 
  
						Estamos criando uma 
						aplicação Web usando ASP.NET Core 1.1 MVC com Entity 
						Framework Core 1.1 e Visual Studio 2017. 
						
						No artigo anterior 
						incluimos novas entidades e relacionamentos em 
						nosso modelo e customizamos o modelo de dados 
						especificando as regras de formatação, validação e 
						mapeamento. Nesta aula vamos continuar a incluir 
						entidades em nosso modelo. 
Criando a entidade Instrutor
Vamos criar uma nova entidade chamada Instrutor na pasta Models do projeto com o seguinte código :
								using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
								namespace UniversidadeMacoratti.Models
{
    public class Instrutor
    {
        public int ID { get; set; }
								        [Required]
        [Display(Name = "Sobrenome")]
        [StringLength(50)]
        public string Sobrenome { get; set; }
								        [Required]
        [Column("Nome")]
        [Display(Name = "Nome")]
        [StringLength(50)]
        public string Nome { get; set; }
								        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "Data de Contratação")]
        public DateTime DataContratacao { get; set; }
								        [Display(Name = "Nome Completo")]
        public string NomeCompleto
        {
            get { return Sobrenome + ", " + Nome; }
        }
								        public ICollection<CursoAtribuido> CursosAtribuidos { get; set; }
        public SalaAtribuida SalaAtribuida { get; set; }
    }
}
								 | 
							
As propriedades CursosAtribuidos e SalaAtribuida são propriedades de navegação.
Um instrutor pode ensinar em diversos cursos, desse modo a propriedade CursosAtribuidos é definida como um conjunto de entidades CursoAtribuido.
Se uma propriedade de navegação pode conter várias entidades, seu tipo deve ser uma lista na qual as entradas podem ser adicionadas, excluídas e atualizadas. Você pode especificar ICollection<T> ou um tipo como List<T> ou HashSet<T>. Se você especificar ICollection<T>, o EF Core vair criar uma coleção HashSet<T> por padrão.
Por outro lado, um instrutor pode ter apenas uma SalaAtribuida, assim a propriedade SalaAtribuida é definida como uma única entidade SalaAtribuida (que pode ser nula se nenhuma sala for atribuída).
Nota: Observe que várias propriedades são as mesmas nas entidades Estudante e Instrutor. Em outro artigo, onde iremos tratar da herança, vamos refatorar este código usando a herança para eliminar esta redundância.
Lembrando que você também pode colocar vários atributos em uma única linha, assim você pode escrever os atributos de DataContratacao da seguinte maneira:
[DataType(DataType.Date), Display(Name = "Data de Contratação"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
Como ainda não criamos as classes CursoAtribuido e SalaAtribuida iremos obter um alerta informando que os tipos não podem ser encontrados. Tudo bem, vamos criar essas classes a seguir.
Criando a entidade SalaAtribuida
Vamos criar a entidade SalaAtribuida criando o o arquivo SalaAtribuida.cs na pasta Models e definindo a classe SalaAtribuida. Clique com o botão direito sobre a pasta Models e selecione Add -> Class, informando o nome SalaAtribuida.cs e a seguir defina o seguinte código nesta classe:
								using System.ComponentModel.DataAnnotations;
								namespace UniversidadeMacoratti.Models
{
    public class SalaAtribuida
    {
        [Key]
        public int InstrutorID { get; set; }
        [StringLength(50)]
        [Display(Name = "Localização da sala")]
        public string Localizacao { get; set; }
								        public Instrutor Instrutor { get; set; }
    }
}
								 | 
							
O atributo Key
Existe uma relação de um para zero ou um entre o instrutor e as entidades 
SalaAtribuida. Uma atribuição de sala só existe em relação ao instrutor que 
está atribuído e, portanto, sua chave primária também é a chave estrangeira para 
a entidade Instrutor. 
Mas o Entity Framework não reconhece automaticamente a propriedade 
InstrutorID como a chave primária desta entidade porque seu nome não segue a 
convenção de nomeação: ID ou classnameID. 
Portanto, o atributo Key é usado para identificar essa propriedade como a 
chave :
[Key]
public int InstrutorID {get; set; }
Você também pode usar o atributo Key se a entidade tiver sua própria 
chave primária, mas você quer dar um nome para a propriedade diferente de 
classnameID ou ID.
Por padrão, a EF trata a chave como não gerada pelo banco de dados porque a 
coluna é para um relacionamento de identificação.
A propriedade de navegação do 
Instrutor
A entidade Instrutor possui uma propriedade de navegação Nullable 
SalaAtribuida(porque um instrutor pode não ter uma sala atribuida) e 
a entidade SalaAtribuida possui uma propriedade de navegação Instrutor 
que é não anulável (porque uma sala não pode existir sem um instrutor -
InstrutorID é não anulável ou non -nullable). 
Dessa forma, quando uma entidade Instrutor possui uma entidade 
SalaAtribuida relacionada, cada entidade terá uma referência á outra 
entidade na sua propriedade de navegação.
Você pode colocar um atributo [Required] na propriedade de navegação 
Instrutor para especificar que deve haver um instrutor relacionado, mas você 
não precisa fazer isso porque a chave estrangeira InstrutorID (que 
também é a chave para esta tabela) é não anulável.
Modificando a entidade Curso
Vamos modificar a entidade Curso abrindo o arquivo Curso.cs na pasta Models e alterando o seu código conforme abaixo:
Obs: O código em azul foi incluído na entidade. Como ainda não criamos a entidade Departamento o VS 2017 vai indicar um erro mas não se preocupe deixe assim por enquanto que mais adiante vamos criar a entidade Departamento.
								using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
								namespace UniversidadeMacoratti.Models
{
    public class Curso
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Display(Name = "Número")]
        public int CursoID { get; set; }
								        [StringLength(50, MinimumLength = 3)]
        public string Titulo { get; set; }
								        [Range(0, 5)]
        public int Creditos { get; set; }
								        public int DepartamentoID { get; set; }
								        public ICollection<Matricula> Matriculas { get; set; }
								        public Departamento Departamento { get; set; }
        public ICollection<CursoAtribuido> CursosAtribuidos { get; set; }
     }
}
								 | 
							
A entidade
Curso possui uma propriedade chave estrangeira DepartamentoID que 
aponta para a entidade Departamento relacionada e possui uma propriedade 
de navegação do Departamento.
O Entity Framework não exige que você adicione uma propriedade de chave 
estrangeira ao seu modelo de dados quando você possui uma propriedade de 
navegação para uma entidade relacionada. 
O EF cria automaticamente chaves estrangeiras na base de dados sempre que elas 
são necessárias e cria propriedades de sombra para elas. Mas ter a chave 
estrangeira no modelo de dados pode tornar as atualizações mais simples e 
eficientes. Por exemplo, quando você busca uma entidade Curso para 
editar, a entidade Departamento é nula se você carregar a entidade, 
então, quando você atualizar a entidade Curso, você deve primeiro buscar 
a entidade Departamento. Quando a propriedade de chave estrangeira 
DepartamentoID está incluída no modelo de dados, você não precisa buscar a 
entidade Departamento antes de atualizar.
O atributo DatabaseGenerated
O atributo DatabaseGenerated com o parâmetro None na propriedade 
CursoID especifica que os valores da chave primária são fornecidos pelo 
usuário em vez de serem gerados pelo banco de dados.
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name = "Número")]
public int CursoID { get; set; }
Por padrão, o Entity Framework assume que os valores da chave primária são 
gerados pelo banco de dados. É o que você quer na maioria dos cenários. No 
entanto, para as entidades Curso, você usará um número de curso 
especificado pelo usuário, como uma série 1000 para um departamento, uma série 
2000 para outro departamento e assim por diante.
O atributo DatabaseGenerated também pode ser usado para gerar valores 
padrão, como no caso de colunas de banco de dados usadas para registrar a data 
em que uma linha foi criada ou atualizada. 
A Propriedade estrangeira e as 
propriedades de navegação
As propriedades das chaves estrangeiras e as propriedades de navegação na 
entidade do Curso refletem os seguintes relacionamentos :
Um curso é atribuído a um departamento, então existe uma chave estrangeira 
DepartamentoID e uma propriedade de navegação Departamento pelos 
motivos mencionados acima.
public int DepartamentoID { get; set; }
public Departamento Departamento { get; set; }
Um curso pode ter qualquer número de alunos matriculados nele, de modo que a 
propriedade de navegação Matriculas é uma coleção:
public ICollection<Matricula> Matriculas { get; set; }
Um curso pode ser ministrado por vários instrutores, de modo que a propriedade 
de navegação CursosAtribuidos é uma coleção (o tipo CursoAtribuido 
que iremos explicar mais adiante):
public ICollection<CursoAtribuido> CursosAtribuidos { 
get; set; }
Criando a entidade Departamento
Clique com o botão direito sobre a pasta Models e selecione Add -> Class, informando o nome Departamento e a seguir defina o seguinte código nesta classe:
								using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
								namespace UniversidadeMacoratti.Models
{
    public class Curso
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Display(Name = "Número")]
        public int CursoID { get; set; }
								        [StringLength(50, MinimumLength = 3)]
        public string Titulo { get; set; }
								        [Range(0, 5)]
        public int Creditos { get; set; }
								        public int DepartamentoID { get; set; }
								        public ICollection<Matricula> Matriculas { get; set; }
								        public Departamento Departamento { get; set; }
        public ICollection<CursoAtribuido> CursosAtribuidos { get; set; }
     }
}
								 | 
							
O atributo Column
Anteriormente, você usou o atributo Column para alterar o mapeamento do 
nome da coluna. No código para a entidade Departamento, o atributo 
Column está sendo usado para alterar o mapeamento do tipo de dados SQL, de 
modo que a coluna será definida usando o tipo money SQL Server.
[Column(TypeName = "money")]
public decimal Orcamento { get; set; }
O mapeamento de colunas geralmente não é necessário, porque o Entity Framework 
escolhe o tipo de dados apropriado do SQL Server com base no tipo CLR que você 
define para a propriedade. O tipo CLR decimal mapeia para um tipo decimal do SQL 
Server. Mas, neste caso, você sabe que a coluna estará mantendo os montantes em 
moeda corrente e o tipo de dados money é mais apropriado para isso.
Propriedade estrangeira e 
propriedades de navegação
A chave estrangeira e as propriedades de navegação refletem as seguintes 
relações:
Um departamento pode ou não ter um administrador, e um administrador é sempre um 
instrutor. Portanto, a propriedade InstrutorID está incluída como a chave 
estrangeira para a entidade Instrutor e um ponto de interrogação(?) é 
adicionado após a designação do tipo int para marcar a propriedade como 
anulável. A propriedade de navegação é denominada Administrador, mas 
possui uma entidade Instrutor:
public int? InstrutorID { get; set; }
public Instrutor Administrador { get; set; }
Um departamento pode ter muitos cursos, então há uma propriedade de navegação 
Cursos:
public ICollection<Curso> Cursos { get; set; }
| 
								
								 
								
								
								modelBuilder.Entity<Departamento>()  | 
							
Modificando a entidade Matricula
Vamos modificar a entidade Matricula abrindo o arquivo Matricula.cs na pasta Models e alterando o seu código conforme abaixo onde incluimos a linha de código em azul:
								using System.ComponentModel.DataAnnotations;
								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; }
        [DisplayFormat(NullDisplayText = "Sem Nota")]
        public Nota? Nota { get; set; }
								        public Curso Curso { get; set; }
        public Estudante Estudante { get; set; }
    }
}
								 | 
							
Propriedade estrangeira e 
propriedades de navegação
As propriedades da chave estrangeira e as propriedades de navegação refletem as 
seguintes relações:
Um registro matricula é para um único curso, então existe uma propriedade de 
chave estrangeira CursoID e uma propriedade de navegação Curso:
public int CursoID { get; set; }
public Curso Curso { get; set; }
Um registro de matricula é para um único aluno, então existe uma propriedade de 
chave estrangeira EstudanteID e uma propriedade de navegação Estudante:
public int EstudanteID { get; set; }
public Estudante Estudante { get; set; }
Relacionamentos muitos para 
muitos
Há uma relacionamento muitos para vários entre as entidades Estudante e Curso 
e a entidade Matricula funciona como uma tabela de junção de 
muitos para muitos com carga útil no banco de dados. "Carga útil" ou "With 
Payload" significa que a tabela Matricula contém dados adicionais 
além de chaves estrangeiras para as tabelas (neste caso, uma chave primária e 
uma propriedade Nota).
A seguinte ilustração mostra como são esses relacionamentos em um diagrama de 
entidades :  

Cada linha 
de relacionamento tem um 1 em uma extremidade e um asterisco (*) na outra, 
indicando um relacionamento  um-para-muitos.
Se a tabela Matricula não incluísse informações de Nota, ela só 
precisaria conter as duas chaves estrangeiras ID do Curso e ID do 
Estudante. Nesse caso, seria uma tabela de junção muitos-para-muitos sem 
carga útil (ou uma tabela de junção pura) no banco de dados. As entidades
Instrutor e Curso possuem esse tipo de relacionamento muitos para 
muitos, e seu próximo passo é criar uma classe de entidade para funcionar como 
uma tabela de junção sem carga útil.
Criando a entidade CursoAtribuido
Clique com o botão direito sobre a pasta Models e selecione Add -> Class, informando o nome CursoAtribuido e a seguir defina o seguinte código nesta classe:
								    public class CursoAtribuido
    {
        public int InstrutorID { get; set; }
        public int CursoID { get; set; }
        public Instrutor Instructor { get; set; }
        public Curso Curso { get; set; }
    }
								 | 
							
Junção de nomes de entidades
Uma tabela de junção é requerida no banco de dados para o relacionamento 
muitos-para-muitos Instrutor-Cursos que deve ser representada por um conjunto de 
entidades.
É comum nomear uma entidade de associação EntityName1EntityName2, que 
neste caso seria CoursoInstrutor. No entanto, recomendamos que você 
escolha um nome que descreva o relacionamento; algo como CursoAtribuicao 
seria melhor que CursoInstrutor.
Chave composta
Uma vez que as chaves estrangeiras não são anuláveis e, juntas, identificam de 
forma exclusiva cada linha da tabela, não há necessidade de uma chave primária 
separada. As propriedades InstrutorID e CursoID devem funcionar como uma 
chave primária composta. 
A única maneira de identificar chaves primárias compostas para o EF é usando a
API fluente (não pode ser feita usando atributos). Você verá como 
configurar a chave primária composta mais adiante em outro artigo.
A chave composta garante que enquanto você pode ter várias linhas para um curso 
e várias linhas para um instrutor, você não pode ter várias linhas para o mesmo 
instrutor e curso. A entidade de junção de Matricula define sua própria 
chave primária, então as duplicatas deste tipo são possíveis. Para evitar tais 
duplicatas, você pode adicionar um índice exclusivo nos campos da chave 
estrangeira ou configurar a Matricula com uma chave composta principal 
semelhante ao CursoAtribuicao. 
Atualizando o contexto do banco de dados
Vamos alterar o código da classe EscolaContexto que representa o nosso contexto do banco de dados incluindo nesta classe o código abaixo em azul:
								using Microsoft.EntityFrameworkCore;
using UniversidadeMacoratti.Models;
								namespace UniversidadeMacoratti.Data
{
    public class EscolaContexto : DbContext
    {
        public EscolaContexto(DbContextOptions<EscolaContexto> options) : base(options)
        {             
        }
								        public DbSet<Curso> Cursos { get; set; }
        public DbSet<Matricula> Matriculas { get; set; }
        public DbSet<Estudante> Estudantes { get; set; }
								        public DbSet<Departamento> Departmentos { get; set; }
        public DbSet<Instrutor> Instrutores { get; set; }
        public DbSet<SalaAtribuida> SalasAtribuidas { get; set; }
        public DbSet<CursoAtribuido> CursosAtribuidos { get; set; }
								        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Curso>().ToTable("Curso");
            modelBuilder.Entity<Matricula>().ToTable("Matricula");
            modelBuilder.Entity<Estudante>().ToTable("Estudante");
								            modelBuilder.Entity<Departamento>().ToTable("Departamento");
            modelBuilder.Entity<Instrutor>().ToTable("Instrutor");
            modelBuilder.Entity<SalaAtribuida>().ToTable("SalaAtribuida");
            modelBuilder.Entity<CursoAtribuido>().ToTable("CursoAtribuido");
								            modelBuilder.Entity<CursoAtribuido>()
                .HasKey(c => new { c.CursoID, c.InstrutorID });
        }
								    }
}
								 | 
							
Este código inclui novas entidades e configura a chave primária composta da entidade CursoAtribuido como sendo CursoID+InstrutorID.
Na próxima aula vamos ver como usar a Fluent API como uma alternativa para definir atributos e definir o código para alimentar o nosso banco de dados e iniciar a aplicação do Migrations.
| 
    
    Veja os 
    Destaques e novidades do SUPER DVD Visual Basic 
(sempre atualizado) : clique e confira ! 
 Quer migrar para o VB .NET ? 
 Quer aprender C# ?? 
 Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?  | 
  
  Gostou ?  
Compartilhe no Facebook
  
 
Compartilhe no Twitter 
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Entity Framework - Conceitos Básicos - Uma visão geral - Macoratti
Entity Framework - Separando as classes das entidades do ... - Macoratti
Entity Framework 6 - Aplicação em camadas - Definindo o ... - Macoratti
C# - Cadastro de Clientes com Entity Framework em ... - Macoratti
NET - Entity Framework 5 - Operações CRUD (revisitado) - Macoratti