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:
- 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!