Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

Duvida entre usar chave primária composta ou não na tabela associativa

Estou fazendo um relacionamento onde o mesmo seja N:N... Exemplo:

Projeto x Funcionario

Neste relacionamento eu crio uma tabela associativa chamada Projeto_Funcionario levando o id das duas classes.

Projeto(id, nome)

Funcionario(id, nome, cargo)

Projeto_Funcionario(idProjeto, idFunc, cargaHoraria)

A dúvida é, gostaria de saber se as chaves idProjeto e idFunc são chaves primárias compostas ou não, ou apenos crio elas sendo estrangeiras e antes dela crio uma primaria.

OBS: O Funcionário não pode trabalhar no mesmo projeto mais de uma vez, apenas uma única vez.

8 respostas
solução!

Olá Renan,

no caso de seu funcionário só poder trabalhar no mesmo projeto apenas uma vez, seria interessante então você usar idProjeto e idFunc como chaves compostas da tabela Projeto_Funcionario além de serem estrangeiras individualmente para as outras tabelas. Isso evitará justamente que o mesmo projeto e funcionario se repitam.

Entendido!

Porém uma dúvida... A classe ja está criada, a migration também (inclusive ja foi rodado o comando update-database), ou seja, a tabela ja está criada.

Depois disso tudo, eu ir no meu context e passar o seguinte comando para haver chave primária composta...

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder
                .Entity<Projeto_Funcionario>()
                .HasKey(pf => new { pf.idProjeto, pf.idFunc});
            base.OnModelCreating(modelBuilder);
        }

...irá fazer alguma alteração na regra da minha tabela, ou não?

Depende muito de como ele tinha mapeado essa relação para o banco antes de você fazer essa mudança no OnModelCreating. Faz um teste, cria mais uma migration com essa mudança e não faz o update. Antes de fazer a atualização, dá uma olhada na classe de migration que ele gerou para ver quais mudanças que ele vai fazer na sua tabela. Dependendo do que ele fizer pode ser que você não tenha que se preocupar com nada que ele vai conseguir converter os dados. Mas se ele mudar muita coisa pode ser que seja necessário fazer alguns updates nos dados junto com essa nova migration para não perder informação.

Pronto, criei um migration e dei uma analisada...

Dê uma olhada no código entre a linha 27 e 37 https://ghostbin.com/paste/c37qu

Fazendo uma análise técnica... Parece que ele atendeu a mudança que fiz no meu context, que no caso foi querer chave primária composta, correto? E por isso fez as seguintes atualizações abaixo:

migrationBuilder.AddPrimaryKey(
name: "PK_Projeto_Funcionario",
table: "Projeto_Funcionario",
columns: new[] { "idProjeto", "idFunc" });

E uma dúvida! Tendo em vista que foi definido chave primária para a tabela (com o método mostrado acima), ele executou o seguinte método, correto?

migrationBuilder.AlterColumn<int>(
name: "ID",
table: "Projeto_Funcionario",
nullable: false);

Viu que a tabela ja tinha chave primária, então fez um AlterColumn, removendo a responsabilidade de chave primária da coluna ID.

Estou correto disso?

Parece que realmente ele removeu a pk do ID e colocou na sua chave composta de idProjeto e idFunc. Só que parece que ele manteve a coluna ID viva ainda. Sua classe Projeto_Funcionario tem uma propriedade ID? Pode ser por isso que ele manteve esta coluna ainda mapeada no banco.

Mantive a coluna ID na classe ainda. Tendo uma chave primária composta, não há necessidade de ter ela? Então posso removê-la?

Exato, você pode apagar dado que que agora está usando a chave composta.

Entendi.

dando um update-database na migration atualizada, foi utilizado o seguinte:

CREATE TABLE [dbo].[Projeto_Funcionario] (
    [idProjeto]    INT             NOT NULL,
    [cargaHoraria] DATE           NOT NULL,
    [idFunc]        INT             NOT NULL,
    CONSTRAINT [PK_Projeto_Funcionario] PRIMARY KEY CLUSTERED ([idProjeto] ASC, [idFunc] ASC),
    CONSTRAINT [FK_Projeto_Funcionario_Projeto_idProjeto] FOREIGN KEY ([idProjeto]) REFERENCES [dbo].[Projeto] ([ID]) ON DELETE CASCADE,
    CONSTRAINT [FK_Projeto_Funcionario_Funcionario_idFunc] FOREIGN KEY ([idFunc]) REFERENCES [dbo].[Funcionario] ([ID]) ON DELETE CASCADE
);

OBS: Destaque na quinta linha do código, onde indica que a tabela foi atualizada para uma chave primária composta e as demais linhas, representando chave estrangeira.