5
respostas

[Dúvida] Não estou conseguindo persistir a Nota no meu Banco

Aparentemente fazendo o debugging ele a lógica está correta, mas apesar dele voltar um 201 e retornar o dado no método Post, quando eu executo o método Get ele volta nulo, porque a nota não foi persistida.

Post:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Get:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

5 respostas

Avaliação:

using ScreenSound.Modelos;

namespace ScreenSound.Shared.Models.Models;

public class AvaliacaoArtista
{
    public virtual Artista? Artista { get; set; }
    public int ArtistaId { get; set; }
    public int PessoaId { get; set; }
    public int Nota { get; set; }

}

Artista:

public string Nome { get; set; }
public string FotoPerfil { get; set; }
public string Bio { get; set; }
public int Id { get; set; }
public virtual ICollection<Musica> Musicas { get; set; } = new List<Musica>();
public virtual ICollection<AvaliacaoArtista> Avaliacoes { get; set; } = new List<AvaliacaoArtista>();
...

public void AdicionarNota(int pessoaId, int nota)
{
    nota = Math.Clamp(nota, 1, 5); // Garante que a nota esteja entre 1 e 5
    Avaliacoes.Add(new AvaliacaoArtista() { ArtistaId = this.Id, PessoaId = pessoaId, Nota = nota });
}

Request:

namespace ScreenSound.API.Requests;

public record AvaliacaoArtistaRequest(int ArtistaId, int Nota);

Response:

using System.ComponentModel.DataAnnotations;

namespace ScreenSound.API.Responses;

public record AvaliacaoArtistaResponse([Required] int ArtistaId, [Required] int Nota);

Program:

builder.Services.AddTransient<DAL<PessoaComAcesso>>();

Endpoint:

// Rota que permite avaliar um artista
groupBuilder.MapPost("avaliacao", (HttpContext context, [FromBody] AvaliacaoArtistaRequest request, [FromServices] DAL<Artista> dalArtista, [FromServices] DAL<PessoaComAcesso> dalPessoaComAcesso) =>
{
    var artista = dalArtista.FindBy(a => a.Id == request.ArtistaId);

    if (artista is null) return Results.NotFound();

    // O ?? é um operador de coalescência nula, que retorna o valor da esquerda se não for nulo, senão o valor da direita
    var email = context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value
        ?? throw new InvalidOperationException("Usuário não autenticado");

    // Se o email não for encontrado, lança uma exceção de InvalidOperationException com a mensagem "Pessoa não encontrada"
    var pessoa = dalPessoaComAcesso.FindBy(p => p.Email == email)
        ?? throw new InvalidOperationException("Pessoa não encontrada");

    // Verifica se a pessoa já avaliou o artista, passando o id do artista e o id da pessoa
    var avaliacao = artista.Avaliacoes.FirstOrDefault(a => a.ArtistaId == artista.Id && a.PessoaId == pessoa.Id);

    // Se a avaliação não existir, adiciona a nota
    if (avaliacao is null)
    {
        // Adiciona a nota
        artista.AdicionarNota(pessoa.Id, request.Nota);
    }
    else
    {
        // Se a avaliação existir, atualiza a nota
        dalArtista.Atualizar(artista);
    }

    return Results.Created();
});

// Rota que busca a nota do artista
groupBuilder.MapGet("{id}/avaliacao", (int id, HttpContext context, [FromServices] DAL<Artista> dalArtista, [FromServices] DAL<PessoaComAcesso> dalPessoa) =>
{
    // Valida se o artista existe
    var artista = dalArtista.FindBy(a => a.Id == id);
    if (artista is null) return Results.NotFound();

    // Verifica se a pessoa está autenticada
    var email = context.User.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.Email))?.Value
        ?? throw new InvalidOperationException("Não foi encontrado o email da pessoa logada");

    // Verifica se a pessoa existe
    var pessoa = dalPessoa.FindBy(p => p.Email!.Equals(email))
        ?? throw new InvalidOperationException("Não foi encontrado o email da pessoa logada");

    // Busca a avaliação do artista feita pela pessoa, passando o id do artista e o id da pessoa
    var avaliacao = artista.Avaliacoes.FirstOrDefault(a => a.ArtistaId == id && a.PessoaId == pessoa.Id);

    // Se a avaliação não existir, retorna 0
    if (avaliacao is null)
    {
        // Retorna a nota 0
        return Results.Ok(new AvaliacaoArtistaResponse(id, 0));
    }
    else
    {
        // Se a avaliação existir, retorna a nota
        return Results.Ok(new AvaliacaoArtistaResponse(id, avaliacao.Nota));
    }

});

Consegui fazer ele persistir o dado no banco, tinha colocado o método atualizar dento do if, mas na verdade ele é fora, pois é ele quem vai persistir meu dado no banco.

Trecho do código do endpoint:

groupBuilder.MapPost...

     // Se a avaliação não existir, adiciona a nota
    if (avaliacao is null)
    {
        // Adiciona a nota
        artista.AdicionarNota(pessoa.Id, request.Nota);
    }
    else
    {
        // Se a avaliação existir, atualiza a nota
        avaliacao.Nota = request.Nota;                
    }

    // Se a avaliação existir, atualiza a nota
    dalArtista.Atualizar(artista);

    return Results.Created();
});

Agora eu estou com um erro que ele não consegue ir lá no meu DB e voltar o dado pra mim. E por conta disso ele está dando erro, porque ele acha que não tem nada e tenta adicionar novamente um dado que já existe.

Verificando o código, tando no Post quando no Get, o trecho que está com problema é onde ele faz a verificação da avaliação, porque está voltando null.

// Verifica se a pessoa já avaliou o artista, passando o id do artista e o id da pessoa
var avaliacao = artista.Avaliacoes.FirstOrDefault(a => a.ArtistaId == artista.Id && a.PessoaId == pessoa.Id);

Essa abordagem seria meio que uma solução para continuar o curso, mas não é bem o foco. Porque o objetivo é popular a coleção de Avaliações em Artistas.

Solução temporária:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

 var avaliacao = artista.Avaliacoes.FirstOrDefault(a => a.ArtistaId == id && a.PessoaId == pessoa.Id);

 var dalAvaliacao = dalAvaliacaoArtista.FindBy(av => av.ArtistaId == id && av.PessoaId == pessoa.Id);

 avaliacao = dalAvaliacao;

De fato a "solução" que eu encontrei ajuda a gravar no banco de dados. Mas essa gambiarra não me dá muitos benefícios, porque eu preciso que a lista em Artista seja populada e eu não estou conseguindo um retorno satisfatório com essa gambiarra, para que a classificação me retorne a média das notas.

Segue o meu github, para ajudar a visualizar o código.

https://github.com/IgorTudisco/Entity-Framework-Core/tree/main/ScreenSound.API

Oi, Igor! Tudo bem?

O problema pode estar na forma como você está carregando os dados do banco. O EF Core, por padrão, não carrega relacionamentos automaticamente. Você precisa garantir que a lista de avaliações está sendo carregada corretamente quando você busca o artista.

Ajuste a consulta para incluir as avaliações usando Include:

var artista = dalArtista
    .FindBy(a => a.Id == id)
    .Include(a => a.Avaliacoes);

Se você estiver usando um repositório genérico, talvez seja necessário modificar o método FindBy para permitir Includings. Agora, se o problema persistir, verifique se o banco realmente tem os dados persistidos. Rode um SELECT diretamente no banco para conferir.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.