Como criar relacionamentos entre entidades?
A abordagem do Entity Framework Code First nos permite criar um modelo como uma classe simples e, em seguida, o banco de dados é criado a partir do modelo de domínio ou da classe de entidade. Na abordagem Code First, o banco de dados é criado a partir das classes.
Algumas vantagens da abordagem do Entity Framework Code First incluem (conforme declarado no blog de Scott Gu):
- Desenvolver sem precisar abrir um designer ou definir um arquivo de mapeamento XML
- Definindo seus objetos de modelo simplesmente escrevendo "classes antigas simples" sem a necessidade de classes base
- Usando uma abordagem de "convenção sobre configuração" que permite a persistência do banco de dados sem configurar explicitamente nada
- Opcionalmente, substituindo a persistência baseada em convenção e usando uma API de código fluente para personalizar totalmente o mapeamento de persistência
Em vez de nos aprofundarmos mais em conceitos teóricos, neste post vamos pular diretamente para o código e criar uma tabela e um banco de dados usando a abordagem Code First. Neste post vamos aprender como podemos criar entidades e uma relação entre entidades na abordagem do Entity Framework Code First. Na abordagem EF Code First, há duas opções para criar a relação entre entidades, por meio de:
- Anotações de dados
- Fluent API
Neste post vamos usar anotações de dados para criar a relação entre entidades.
Criar banco de dados com uma tabela
Vamos começar criando uma tabela chamada Student em um banco de dados com a abordagem code first. A classe de domínio Student pode ser criada conforme mostrado na listagem abaixo:
namespace CodeFirstDemoApp { public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } }
Como você já deve ter notado, a classe Student é uma classe simples. O Entity Framework usará a classe Student para criar a tabela no banco de dados. A classe Student representa a entidade de domínio e não deve ter nenhuma informação ou referência do banco de dados. O Entity Framework usará a classe Student para criar a tabela Student.
Depois que a classe de entidade de domínio for criada, em seguida, precisamos criar uma classe Context que herdará a classe DataContext. A classe de contexto pode ser criada conforme mostrado na listagem abaixo:
using System.Data.Entity; namespace CodeFirstDemoApp { public class Context : DbContext { public Context() : base() { } public DbSet<Student> Students { get; set; } } }
Criamos a classe Context com o construtor padrão. Mais adiante no post falaremos sobre várias opções no construtor. Na classe de contexto, estamos fazendo as seguintes tarefas:
- Criando o construtor padrão. Como não estamos passando nenhum parâmetro no construtor, o EF criará um banco de dados com o nome como nome Namespace.Class. Portanto, nesse caso, o nome do banco de dados criado será CodeFirstDemo.Context.
- Como não estamos passando informações de cadeia de conexão no construtor da classe Context, o EF criará um banco de dados no servidor de banco de dados padrão do SQL Server Express.
- Para criar um banco de dados no servidor desejado com o nome desejado, precisamos criar a cadeia de conexão e passá-la como um parâmetro no construtor Context.
- Para criar a tabela no banco de dados, crie uma propriedade pública do tipo DbSet genérico com a entidade de domínio passada nela.
Até agora, criamos a classe de entidade Student e a classe Context. Agora podemos escrever uma consulta LINQ to Entity simples para criar o banco de dados e executar as operações, conforme mostrado na listagem abaixo:
using System; using System.Linq; namespace CodeFirstDemoApp { class Program { static void Main(string[] args) { CreateStudent(); Console.WriteLine("Student Created"); using (Context c = new Context()) { var result = from r in c.Students select r; foreach (var r in result) { Console.WriteLine(r.Name); } } Console.ReadKey(true); } static void CreateStudent() { Student s = new Student { Id = 1, Age = 12, Name = "Foo" }; using (Context c = new Context()) { c.Students.Add(s); c.SaveChanges(); } } } }
Custom Database Name
Quando trabalhamos com o construtor padrão para a classe Context, o EF, por padrão, cria o banco de dados com um nome totalmente qualificado como nome Namespace.Contextclass. No entanto, podemos passar o nome desejado do banco de dados mydb neste caso no construtor, conforme mostrado na listagem abaixo:
public Context() : base("mydb") {}
No SQL Express, o EF criará um banco de dados com o nome mydb.
Trabalhando com cadeia de conexão
A partir de agora, estamos contando com o EF para criar o banco de dados. No entanto, podemos passar uma string de conexão para criar um banco de dados no servidor desejado e um nome. A cadeia de conexão pode ser criada no arquivo de configuração, conforme listado abaixo:
<connectionStrings> <add name="democonnectionstring" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=Demo1;Integrated Security=True;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" /></connectionStrings>
Criamos uma string de conexão para criar um banco de dados no servidor de banco de dados local. Em seguida, precisamos passar o nome da cadeia de conexão no construtor da classe Context, conforme mostrado na listagem abaixo:
public Context() : base("name=democonnectionstring") {}
Relationship Between Entities
Na abordagem Code First, podemos criar uma relação entre entidades usando uma das duas opções:
- Anotações de dados
- Fluent API
Neste post vamos criar relacionamento usando anotações de dados.
Relacionamento um-para-um
Podemos ter um requisito para criar relacionamentos individuais entre duas entidades. Em outras palavras, precisamos de uma relação de chave primária – chave estrangeira entre duas entidades. Digamos que temos duas entidades e as seguintes regras:
- Há duas entidades chamadas Student e StudentAccount
- O aluno é uma entidade primária
- StudentAccount é uma entidade dependente de Student
- A chave primária de StudentAccount será a chave estrangeira de Student
Não devemos criar uma StudentAccount sem um Student e só pode haver uma entrada de Student em StudentAccount. Simplificando, cada Aluno terá uma StudentAccount e nenhuma StudentAccount existirá sem um Student.
Vamos primeiro criar a entidade principal: Aluno
public class Student { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public virtual StudentAccount StudentAccount { get; set; } }
Como você deve ter notado, na entidade Student temos uma propriedade virtual do tipo StudentAccount que é criada conforme mostrado na listagem abaixo:
public class StudentAccount { public int Id { get; set; } public string Name { get; set; } public int Amount { get; set; } [Required] public virtual Student Student { get; set; } }
Novamente, você deve ter notado que, na entidade StudentAccount, temos uma propriedade virtual do tipo Student. Como Student é uma entidade primária, a propriedade virtual Student na entidade StudentAccount é anotada como Required. Além disso, uma classe Context pode ser criada conforme mostrado na listagem abaixo:
using System.Data.Entity; namespace CodeFirstDemoApp { public class Context : DbContext { public Context() : base("name=democonnectionstring") {} public DbSet<Student>Students { get; set; } public DbSet<StudentAccount>StudentAccounts { get; set; } } }
Lembre-se sempre de que não podemos criar uma linha na tabela StudentAccounts, a menos que não tenhamos uma linha correspondente na tabela Student. Os dados podem ser criados na tabela relacionada, conforme mostrado na listagem abaixo:
static void CreateStudent() { Student s=new Student { Id=1, Age=12, Name="Foo" }; StudentAccount sa=new StudentAccount { Amount=300, Name="Sports Account", Student=s }; Context c=new Context(); c.Students.Add(s); c.StudentAccounts.Add(sa); c.SaveChanges(); }
Como você deve ter notado, estamos definindo o objeto de Student como uma propriedade de StudentAccount. Podemos recuperar registros de ambas as tabelas, conforme mostrado na listagem abaixo:
Context c=new Context(); var result=from r in c.Students select r; foreach (var r in result) { Console.WriteLine(r.Name); Console.WriteLine(r.StudentAccounts.Amount); }
Para verificar a relação entre entidades no SQL Server Management Studio, podemos ver as colunas criadas com as restrições e chaves como mostra a imagem abaixo:

Aqui, a coluna Id da tabela StudentAccounts é a chave primária e a chave estrangeira.
Relacionamento Um para Muitos
Podemos ter a necessidade de criar um relacionamento demais entre duas entidades. Digamos que temos duas entidades
- Há duas entidades: Student e StudentAddress
- O aluno é uma entidade primária
- StudentAddress é uma entidade dependente de Student
- Um aluno pode se inscrever em vários StudentAddress
Um aluno pode ter muitos StudentAddress. Uma das colunas de StudentAddress terá a chave estrangeira como chave primária de Student.
Vamos primeiro criar a entidade primária Student,
public class Student { public Student() { StudentAddresses=new HashSet<StudentAddress>(); } public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public ICollection<StudentAddress>StudentAddresses { get; set; } }
Você deve ter notado que estamos criando uma propriedade de coleção de StudentAddress e, em seguida, criando um valor definido da propriedade StudentAddress no construtor de Student. A classe StudentAddress pode ser criada conforme mostrado na listagem abaixo:
public class StudentAddress { public int Id { get; set; } public string Address { get; set; } public int StudentId { get; set; } public virtual Student Student { get; set; } }
Novamente, você deve ter notado que, na entidade StudentAddress, temos uma propriedade virtual do tipo Student. Como Student é uma entidade primária, a propriedade virtual Student no StudentAddress tem uma propriedade StudentId correspondente.
Além disso, a classe Context pode ser criada conforme mostrado na listagem abaixo:
public class Context : DbContext { public Context() : base("name=democonnectionstring") {} public DbSet<Student>Students { get; set; } public DbSet<StudentAddress>StudentAddresses { get; set; } }
Lembre-se sempre de que não podemos criar uma linha na tabela StudentAddress, a menos que não tenhamos uma linha correspondente na tabela Student. Os dados podem ser criados na tabela relacionada, conforme mostrado na listagem abaixo:
static void CreateStudent() { Student s=new Student { Id=1, Age=12, Name="Foo" }; StudentAddress sa1=new StudentAddress { Address="Delhi", Id=1 }; StudentAddress sa2=new StudentAddress { Address="Bangalore", Id=2 }; s.StudentAddresses.Add(sa1); s.StudentAddresses.Add(sa2); Context c=new Context(); c.Students.Add(s); c.SaveChanges(); }
Como você deve ter notado, estamos adicionando os objetos de StudentAddress ao Student. Podemos recuperar registros de ambas as tabelas, conforme mostrado na listagem abaixo:
static void Main(string[] args) { CreateStudent(); Console.WriteLine("Student Created"); Context c=new Context(); var result=from r in c.Students.Include("StudentAddresses") select r; foreach (var r in result) { Console.WriteLine(r.Name); foreach(var a in r.StudentAddresses) { Console.WriteLine(a.Address); } } Console.ReadKey(true); }
Para verificar a relação entre entidades no SQL Server Management Studio, podemos ver as colunas criadas com as restrições e chaves como mostra a imagem abaixo:

Many to Many Relationship
Por último, mas não menos importante, vamos ver como podemos configurar uma relação muitos para muitos. Digamos que temos uma entidade Student e uma entidade Subject. Um aluno pode estar matriculado em muitas disciplinas e uma disciplina pode ter muitos alunos. Para criar muitos relacionamentos entre essas entidades, vamos primeiro criar a entidade Student, conforme mostrado na listagem abaixo:
public class Student { public Student() { Subjects=new HashSet<Subject>(); } public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public ICollection<Subject>Subjects { get; set; } }
Aqui, estamos criando uma propriedade de coleção de Subjects e, em seguida, criando um valor definido da propriedade Subjects no construtor de Student. A classe Subject pode ser criada conforme mostrado na listagem abaixo:
public class Subject { public Subject() { Students=new HashSet<Student>(); } public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Student>Students { get; set; } }
Na classe Subject também estamos criando a propriedade da coleção de Students e no construtor da classe Subject criando um conjunto de alunos. Isso é tudo o que precisamos fazer para criar muitos relacionamentos entre entidades.
Além disso, a classe Context pode ser criada conforme mostrado na listagem abaixo:
public class Context : DbContext { public Context() : base("name=democonnectionstring") {} public DbSet<Student>Students { get; set; } public DbSet<Subject>Subjects { get; set; } }
Podemos criar as linhas na tabela Alunos e Assuntos, conforme mostrado na listagem abaixo:
static void CreateStudent() { Student s=new Student { Id=1, Age=12, Name="Foo" }; Subject s1=new Subject { Id=1, Name="Phy" }; Subject s2=new Subject { Id=2, Name="Maths" }; s.Subjects.Add(s1); s.Subjects.Add(s2); Context c=new Context(); c.Students.Add(s); c.SaveChanges(); }
Podemos recuperar registros de ambas as tabelas, conforme mostrado aqui:
static void Main(string[] args) { CreateStudent(); Console.WriteLine("Student Created"); Context c=new Context(); var result=from r in c.Students.Include("Subjects") select r; foreach (var r in result) { Console.WriteLine(r.Name); foreach(var a in r.Subjects) { Console.WriteLine(a.Name); } } Console.ReadKey(true); }
Quando verificarmos a relação entre a entidade Aluno e Assunto, descobriremos que a EF criou uma tabela extra para manter a relação muitos para muitos

Então, aí está, é assim que se cria relacionamentos entre entidades na abordagem Code First. Neste post, começamos trabalhando com entidades únicas e, em seguida, criamos um relacionamento entre as entidades. Espero que você ache este post útil, obrigado por ler.
Infragistics Ultimate 15.2 está aqui.Baixee veja seu poder em ação!
