Introdução aos relacionamentos

Esta documentação fornece uma introdução simples à representação de relacionamentos em modelos de objetos e bancos de dados relacionais, incluindo como fazer os mapeamentos do Entity Framework Core entre os dois.

Relacionamentos em modelos de objetos

Um relacionamento define como duas entidades se relacionam entre si. Por exemplo, ao modelar postagens em um blog, cada postagem está relacionada ao blog no qual foi publicada, e o blog está relacionado a todas as postagens publicadas nesse blog.

Em uma linguagem orientada a objetos como o C#, o blog e a postagem são normalmente representados por duas classes: Blog e Post. Por exemplo:

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }
}
public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }
}

Nas classes acima, não existe nada que indique que Blog e Post estão relacionados. Isso pode ser adicionado em um modelo de Objeto adicionando uma referência de Post ao Blog no qual ele está publicado:

public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateOnly PublishedOn { get; set; }
    public bool Archived { get; set; }

    public Blog Blog { get; set; }
}

Da mesma forma, a direção oposta do mesmo relacionamento pode ser representada como uma coleção de objetos Post em cada Blog:

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}

Essa conexão de Blog para Post e, inversamente, de Post para Blog é conhecida como "relacionamento" no Entity Framework Core.

Importante

Um relacionamento único pode ser normalmente percorrido em qualquer direção. Neste exemplo, isso é de Blog para Post por meio da propriedade Blog.Posts e de Post de volta para Blog por meio da propriedade Post.Blog. Esse é um relacionamento um, não dois.

Dica

No Entity Framework Core, as propriedades Blog.Posts e Post.Blog são chamadas de "navegações".

Relacionamentos em bancos de dados relacionais

Os bancos de dados relacionais representam relacionamentos utilizando chaves estrangeiras. Por exemplo, usando o SQL Server ou o SQL do Azure, as tabelas a seguir podem ser utilizadas para representar nossas classes Post e Blog:

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    [PublishedOn] datetime2 NOT NULL,
    [Archived] bit NOT NULL,
    [BlogId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]) ON DELETE CASCADE);

CREATE TABLE [Blogs] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NULL,
    [SiteUri] nvarchar(max) NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]));

Nesse modelo relacional, as tabelas Posts e Blogs recebem, cada uma, uma coluna de "chave primária". O valor da chave-valor primária identifica de forma exclusiva cada postagem ou blog. Além disso, a tabela Posts recebe uma coluna de "chave estrangeira". A coluna Blogs de chave primária Id é referenciada pela coluna BlogId de chave estrangeira da tabela Posts. Essa coluna é "restrita" de modo que qualquer valor na coluna BlogId de Postsdeve corresponder a um valor na coluna Id de Blogs. Essa correspondência determina a qual blog cada postagem está relacionada. Por exemplo, se o valor BlogId em uma linha da tabela Posts for 7, então a postagem representada por essa linha será publicada no blog com a chave primária 7.

Mapeamentos de relacionamentos no Entity Framework Core

O mapeamento do relacionamento do Entity Framework Core consiste em mapear a representação de chave primária/chave estrangeira usada em um banco de dados relacional para as referências entre objetos utilizados em um modelo de objeto.

No sentido mais básico, isso envolve:

  • Adição de uma propriedade de chave primária para cada tipo de entidade.
  • Adição de uma propriedade de chave estrangeira para um tipo de entidade.
  • A associação das referências entre os tipos de entidades com as chaves primárias e estrangeiras para formar uma única configuração de relacionamento.

Uma vez feito esse mapeamento, o EF altera os valores da chave estrangeira conforme necessário quando as referências entre os objetos são alteradas e altera as referências entre os objetos conforme necessário quando os valores da chave estrangeira são alterados..

Observação

As chaves primárias são utilizadas para mais do que mapeamentos de relacionamentos. Consulte Chaves para obter mais informações.

Por exemplo, os tipos de entidade mostrados acima podem ser atualizados com propriedades de chave primária e chave estrangeira:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}
public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

Dica

As propriedades de chave primária e estrangeira não precisam ser propriedades publicamente visíveis do tipo de entidade. Entretanto, mesmo quando as propriedades estão ocultas, é importante reconhecer que elas ainda existem no modelo do EF.

A propriedade Chave primária de Blog, Blog.Id e a propriedade Chave estrangeira de Post, Post.BlogId podem então ser associadas às referências ("navegações") entre os tipos de entidade (Blog.Posts e Post.Blog). Isso é feito automaticamente pelo EF ao criar um relacionamento simples como esse, mas também pode ser especificado explicitamente ao substituir o método OnModelCreating do seu DbContext. Por exemplo:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .HasPrincipalKey(e => e.Id);
}

Agora, todas essas propriedades se comportarão de forma coerente como uma representação de um único relacionamento entre Blog e Post.

Saiba mais

A EF dá suporte a muitos diferentes tipos de relacionamentos, com muitas maneiras diferentes de representar e configurar esses relacionamentos. Para ver exemplos de diferentes tipos de relacionamentos, consulte:

Se você é novo no EF, experimentar os exemplos relacionados nos pontos acima é uma boa maneira de ter uma ideia de como os relacionamentos funcionam.

Para se aprofundar nas propriedades dos tipos de entidades envolvidas no mapeamento de relacionamentos, consulte:

Os modelos EF são criados utilizando uma combinação de três mecanismos: convenções, atributos de mapeamentos e a API do construtor de modelos. A maioria dos exemplos mostra a API de criação de modelos. Para encontrar outras opções, consulte:

Importante

A API de criação de modelos é a fonte final da verdade para o modelo EF, ela sempre tem precedência sobre a configuração descoberta por convenção ou especificada por atributos de mapeamento. É também o único mecanismo com total fidelidade para configurar todos os aspectos do modelo do EF.

Outros tópicos relacionados a relacionamentos incluem:

  • Excluir em cascata, que descreve como as entidades relacionadas podem ser automaticamente excluídas quando SaveChanges ou SaveChangesAsync é chamado.
  • Tipos de entidades proprietárias utilizam um tipo especial de relacionamento "proprietário" que implica uma conexão mais forte entre os dois tipos ao invés dos relacionamentos "normais" discutidos aqui. Muitos dos conceitos descritos aqui para relacionamentos normais são transferidos para relacionamentos proprietários. Entretanto, os relacionamentos com proprietários também têm seus próprios comportamentos especiais.

Dica

Consulte o glossário de termos do relacionamento conforme necessário ao ler a documentação para ajudar a entender a terminologia utilizada.

Usando relacionamentos

Os relacionamentos definidos no modelo podem ser utilizados de várias maneiras. Por exemplo: