Resumo : neste tutorial, você aprenderá sobre relacionamentos um-para-muitos e como implementá-los no EF Core.
Introdução aos relacionamentos um-para-muitos
No banco de dados relacional, um relacionamento um-para-muitos é um tipo comum de relacionamento entre duas tabelas em que uma linha de uma tabela pode ser associada a várias linhas de outra tabela.
Por exemplo, um departamento pode ter vários funcionários enquanto um funcionário pertence a um departamento. Portanto, o Departments
tem um relacionamento um-para-muitos com a Employees
tabela.
O relacionamento um-para-muitos também é conhecido como relacionamento pai-filho. A Departments
é chamada de tabela pai, enquanto a Employees
tabela é chamada de tabela filha.
Para estabelecer o relacionamento um-para-muitos entre as tabelas Departments
e Employees
, a Employees
tabela precisa ter uma coluna de chave estrangeiraDepartmentId
chamada que faça referência à Id
coluna da Employees
tabela:
Se a DepartmentId
coluna aceitar NULL
, você poderá inserir uma linha na Employees
tabela sem especificar uma linha correspondente na Departments
tabela. Neste caso, o funcionário não pertence a nenhum departamento.
No entanto, se a DepartmentId
coluna não aceitar NULL
, você precisará usar um Id
da Departments
tabela para inserir uma nova linha na Employees
tabela. Neste caso, o funcionário deve pertencer a um departamento específico. Em outras palavras, você precisa ter pelo menos uma linha na Departments
tabela antes de poder inserir linhas na Employees
tabela.
Demonstraremos cenários típicos para que você possa modelar relacionamentos um-para-muitos entre entidades. Para cenários abrangentes, você pode consultar esta página .
A modelagem exigia relacionamento um-para-muitos
Veja a seguir como modelar um relacionamento um-para-muitos necessário entre as entidades Department
e :Employee
public class Department
{
public int Id { get; set; }
public required string Name { get; set; }
// Collection navigation containing children
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public required string FirstName { get; set; }
public required string LastName { get; set; }
public required decimal Salary { get; set; }
public required DateTime JoinedDate { get; set; }
// Required foreign key property
public int DepartmentId { get; set; }
// Required reference navigation to parent
public Department Department { get; set; } = null!;
}
Linguagem de código: C# ( cs )
Neste exemplo:
- A
Department
classe possui uma propriedade que é uma coleção deEmployee
objetos. - A
Employee
classe tem duas propriedadesDepartmentId
eDepartment
. ODepartmentId
é chamado de propriedade de chave estrangeira , que é marcado como obrigatório. Isso torna o relacionamento um-para-muitos obrigatório porque cada umEmployee
deve se associar a pelo menos um arquivoDepartment
. ADepartment
propriedade é conhecida como propriedade de navegação .
Com base neste modelo, o EF Core gera a tabela Departments
e Employees
no banco de dados SQL Server com a seguinte estrutura:
CREATE TABLE [dbo].[Departments] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NOT NULL,
CONSTRAINT [PK_Departments] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE [dbo].[Employees] (CREATE TABLE [dbo].[Employees] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[FirstName] NVARCHAR (MAX) NOT NULL,
[LastName] NVARCHAR (MAX) NOT NULL,
[Salary] DECIMAL (18, 2) NOT NULL,
[JoinedDate] DATETIME2 (7) NOT NULL,
[DepartmentId] INT NOT NULL,
CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Employees_Departments_DepartmentId] FOREIGN KEY ([DepartmentId]) REFERENCES [dbo].[Departments] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_Employees_DepartmentId]
ON [dbo].[Employees]([DepartmentId] ASC);
Linguagem de código: SQL (linguagem de consulta estruturada) ( sql )
Observe que a DepartmentId
coluna da Employees
tabela não é NULL. Além disso, é uma chave estrangeira que faz referência à Id
coluna da Departments
tabela.
Modelando o relacionamento um-para-muitos opcional
O seguinte altera a DepartmentId
propriedade de chave estrangeira e Departments
a propriedade de navegação da Employee
classe para anulável:
public class Department
{
public int Id { get; set; }
public required string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public required string FirstName { get; set; }
public required string LastName { get; set; }
public required DateTime JoinedDate { get; set; }
public int? DepartmentId { get;set; }
public Department? Department { get; set; }
}
Linguagem de código: C# ( cs )
Como as propriedades DepartmentId
and Department
são anuláveis, você pode criar um Employee
objeto sem um Department
.
O EF Core cria o seguinte Departments
e Employees
tabelas no banco de dados. Observe que o DepartmentId
na Employees
tabela aceita NULL:
CREATE TABLE [dbo].[Departments] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NOT NULL,
CONSTRAINT [PK_Departments] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[Employees] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[FirstName] NVARCHAR (MAX) NOT NULL,
[LastName] NVARCHAR (MAX) NOT NULL,
[JoinedDate] DATETIME2 (7) NOT NULL,
[DepartmentId] INT NULL,
CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Employees_Departments_DepartmentId] FOREIGN KEY ([DepartmentId]) REFERENCES [dbo].[Departments] ([Id])
);
GO
CREATE NONCLUSTERED INDEX [IX_Employees_DepartmentId]
ON [dbo].[Employees]([DepartmentId] ASC);
Linguagem de código: SQL (linguagem de consulta estruturada) ( sql )
Resumo
- O EF Core usa convenções para inferir os relacionamentos um-para-muitos entre as classes do modelo e criar as tabelas correspondentes no banco de dados.