0
respostas

[Sugestão] Problema para deletar Artistas que possuem Músicas

Pessoal, boa tarde!

Recebi uma mensagem de erro como retorno ao tentar usar a funcionalidade de Deletar Artistas que fizemos na aula 07 do módulo "Montando uma API mínima", que era a seguinte:

Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details. ---> Microsoft.Data.SqlClient.SqlException (0x80131904): The DELETE statement conflicted with the REFERENCE constraint "FK_Musicas_Artistas_ArtistaId". The conflict occurred in database "ScreenSoundV0", table "dbo.Musicas", column 'ArtistaId'.

A situação aqui é que: o artista que eu tentei excluir tinha música(s) associada a ele na tabela de Músicas, vinculada pelo id do Artista, o que acaba bloqueando a deleção desse artista (pelo menos por padrão).

No exemplo que o professor deletou na aula, o artista que ele excluiu não tinha músicas, se eu não estiver enganado, então não teve esse erro sendo levantado pelo sistema.

O caminho que resolvi seguir para solucionar isso foi a configuração do ScreenSoundContext para aceitar deleção em cascata na tabela de músicas, ou seja, se um artista for deletado, todas as músicas associadas a ele também serão, e decidi abrir esse Tópico para auxiliar alguém que também passe por esse problema.

Considerando o código visto em aula:

app.MapDelete("/Artistas/{id}", ([FromServices] DAL<Artista> DAL, int id) =>
{
    var artista = DAL.RecuperarPor(a => a.Id == id);
    if (artista is null) return Results.NotFound();

    DAL.Deletar(artista);
    return Results.NoContent();
});
Segue o passo a passo:
  1. Modificar o arquivo Musica.cs

Para que essa estratégia funcione, precisamos adicionar explicitamente uma propriedade de chave estrangeira. Atualmente, nossa classe modelo Musica tem a navegação Artista, mas não tem um campo ArtistaId, que é necessário para o mapeamento correto. É isso que iremos adicionar a ela:

namespace ScreenSound.Modelos;

public class Musica
{
    public Musica(string nome, int? anoLancamento = null)
    {
        Nome = nome;
        AnoLancamento = anoLancamento;
    }

    public string Nome { get; set; }
    public int Id { get; set; }
    public int? AnoLancamento { get; set; }
    public int? ArtistaId { get; set; } //Propriedade nova que adicionamos
    public virtual Artista? Artista { get; set; } 

    public void ExibirFichaTecnica()
    {
        Console.WriteLine($"Nome: {Nome}");
      
    }

    public override string ToString()
    {
        return @$"Id: {Id}
        Nome: {Nome}
        Ano de Lançamento: {AnoLancamento}";
    }
}
2. Modificar o arquivo ScreenSoundContext.cs

Na nossa classe contexto, iremos adicionar a configuração de OnDelete(DeleteBehavior.Cascade) na entidade Musica:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Musica>()
        .HasOne(m => m.Artista)
        .WithMany(a => a.Musicas)
        .HasForeignKey(m => m.ArtistaId)
        .OnDelete(DeleteBehavior.Cascade);
}

3.Atualizar o banco de dados

Após essas alterações, precisamos atualizar o nosso banco de dados, tal qual como aprendemos no curso anterior a esse, utilizando migrations, então iremos:

  • Abrir o Package Manager Console do Visual Studio;
  • Verificar e garantir que o campo Default Project está associado ao projeto que o nosso ScreenSoundContext está (no nosso caso: ScreenSound.Shared.Dados)
  • Criar uma migration:
Add-Migration nomeDaMigration
  • Atualizar o banco de dados:
Update-Database
Feito isso, nossa API já estará pronta para conseguir deletar artistas que tenham músicas cadastradas, e irá deletar essas músicas junto, de acordo com a configuração que montamos.

Espero que isso possa ajudar quem encontrar algum problema parecido. Estou aberto a opniões e sugestões de outros caminhos que poderiam ter sido seguidos. Muito obrigado a todos!