3
respostas

Na Consulta https://localhost:7089/Artistas/Djavan - "Artista": null nos campos da Música

Eu fiz o curso do EntityFramework e estou realizando o de Web API. Solicito orientação para entender porque na estrutura do Json dos campos Música, o campo Artista fica com null. É algo que foi explicado no curso anterior que porventura eu não tenha percebido?
Estrutura retornada abaixo:
{"musicas":[{"nome":"Oceano","id":5,"anoLancamento":1989,"artista":null},{"nome":"Flor de Lis","id":6,"anoLancamento":1976,"artista":null},{"nome":"Samurai","id":7,"anoLancamento":1982,"artista":null},{"nome":"Se","id":8,"anoLancamento":1992,"artista":null}],"lazyLoader":{},"nome":"Djavan","fotoPerfil":"https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png","bio":"Djavan Caetano Viana é um cantor, compositor, arranjador, produtor musical, empresário, violonista e ex-futebolista brasileiro.","id":1}

3 respostas

Olá José.
Vamos tentar entender o que está acontecendo.
No Entity Framework, se o relacionamento entre Musica e Artista não for explicitamente carregado ou se o campo artista não for mapeado para ser incluído nas respostas, ele pode aparecer como null na resposta JSON.
Se o Artista não estiver sendo carregado corretamente ao buscar as músicas, o valor de artista no JSON será null.
Outra possibilidade é que a entidade Musica tem um campo Artista, mas o banco de dados não tem dados válidos para preencher esse campo. Ou seja, a música pode estar associada a um artista com valor null no banco, o que fará com que o campo artista no JSON seja null. Se o relacionamento entre as tabelas no banco de dados não tiver sido preenchido corretamente (por exemplo, se ArtistaId for null ou inválido), o valor de artista será null.
Se a resposta JSON estiver sendo manipulada por um DTO ou uma transformação antes de ser enviada para o cliente, pode ser que o campo artista esteja sendo omitido ou não esteja sendo preenchido corretamente.
Resumindo não ha nada demais em estar preenchido como null e se quiser listar o artista vai precisar alterar o código e certificar que o campo artista no banco de dados não esteja vazio.
A motivação para o campo artista ser null é uma questão de carregamento de dados. Ou o artista não está sendo carregado corretamente na consulta, ou não existe um valor válido no banco de dados para preenchê-lo, ou a resposta JSON não está incluindo corretamente a propriedade artista.
Espero que minha resposta tenha ajudado.
Senão comente ai.
Bons estudos.

Oi Ronaldo. Sou iniciante no tema Entity Framework. Fiz o curso .NET: persistindo dados com Entity Framework Core que continua o projeto ScreenSound que veio do Curso de Orientação a Objetos. O curso NET: criando uma API Web com ASP.NET Core, em curso, continua o projeto ScreenSound que veio do curso Entity. O mapeamento das classes, criação do banco de dados e tabelas foi feito naquele curso.
A tabela Musicas contém o ArtistaID que é foreign key para a tabela Musicas:
ALTER TABLE [dbo].[Musicas] WITH CHECK ADD CONSTRAINT [FK_Musicas_Artistas_ArtistaId] FOREIGN KEY([ArtistaId])
REFERENCES [dbo].[Artistas] ([Id])
GO.
Id Nome AnoLancamento ArtistaId
5 Oceano 1989 1
6 Flor de Lis 1976 1
7 Samurai 1982 1
8 Se 1992 1

Na tabela Artistas há o Id 1 para o cantor Djavan.

Eu gostaria de saber como precisará ser feito o mapeamento para que o Id do Artista seja incluído no objeto Musicas no Json de reposta:
{"musicas":[{"nome":"Oceano","id":5,"anoLancamento":1989,"artista":null},

Caso alguém tenha acesso ao projeto, segue o link. Do contrário, verei com o instrutor do curso de Web API.

Agradeço a atenção.

Não vamos desistir ainda.
Vamos entender o que está acontecendo e como resolver.

O problema

Você tem duas entidades:

public class Musica
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public int AnoLancamento { get; set; }

    // Chave estrangeira
    public int ArtistaId { get; set; }

    // Propriedade de navegação
    public Artista? Artista { get; set; }
}

e

public class Artista
{
    public int Id { get; set; }
    public string Nome { get; set; }
    public string FotoPerfil { get; set; }
    public string Bio { get; set; }

    // Relacionamento 1:N
    public ICollection<Musica> Musicas { get; set; } = new List<Musica>();
}

O mapeamento no banco está correto.
A foreign key existe e o relacionamento está definido.
O motivo de artista estar null no JSON** é que o Entity Framework Core, por padrão, não carrega as entidades relacionadas automaticamente quando você faz uma consulta simples.

Entendendo o comportamento

Quando você faz algo assim:

var musicas = _context.Musicas.ToList();

O EF Core só carrega os dados da tabela Musicas, não faz o "join" automático com Artistas.
Por isso, ao serializar o objeto Musica para JSON, o campo Artista está null.

Solução: usar Eager Loading com .Include()

Para trazer também o artista de cada música, você precisa usar o método Include, do namespace Microsoft.EntityFrameworkCore:

using Microsoft.EntityFrameworkCore;

// ...

var musicas = _context.Musicas
    .Include(m => m.Artista)
    .ToList();

Agora, cada objeto Musica terá o campo Artista populado corretamente, e o JSON ficará assim:

{
  "musicas": [
    {
      "id": 5,
      "nome": "Oceano",
      "anoLancamento": 1989,
      "artista": {
        "id": 1,
        "nome": "Djavan",
        "fotoPerfil": "https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png",
        "bio": "Djavan Caetano Viana é um cantor, compositor..."
      }
    }
  ]
}

Caso esteja usando uma API mínima (Minimal API)

Se o seu endpoint estiver assim:

app.MapGet("/musicas", (ScreenSoundContext context) =>
{
    var musicas = context.Musicas.ToList();
    return Results.Ok(new { musicas });
});

Basta alterar para:

app.MapGet("/musicas", (ScreenSoundContext context) =>
{
    var musicas = context.Musicas
        .Include(m => m.Artista)
        .ToList();

    return Results.Ok(new { musicas });
});

Outras formas de carregar os dados

Existem três formas de o EF Core carregar dados relacionados:

TipoComo fazQuando usar
Eager Loading.Include(m => m.Artista)Quando você sabe que vai precisar dos dados relacionados.
Lazy LoadingCarrega automaticamente quando acessa a propriedade (m.Artista) — requer configuração especial.Quando quer carregar sob demanda.
Explicit LoadingUsa .Entry(m).Reference(x => x.Artista).Load() manualmente.Quando quer controle total.

O curso de Entity Framework possivelmente mostrou o relacionamento e as classes, mas no curso da API você ainda precisa explicitamente incluir os dados com .Include(), já que o EF não faz isso automaticamente.
Se você quer simplificar o JSON (por exemplo, evitar que o Artista venha com a lista de músicas, o que pode causar loop de referência), pode usar um DTO:

public record MusicaDTO(int Id, string Nome, int AnoLancamento, string Artista);

e no endpoint:

app.MapGet("/musicas", (ScreenSoundContext context) =>
{
    var musicas = context.Musicas
        .Include(m => m.Artista)
        .Select(m => new MusicaDTO(m.Id, m.Nome, m.AnoLancamento, m.Artista!.Nome))
        .ToList();

    return Results.Ok(new { musicas });
});

Isso evita problemas de serialização circular e deixa a resposta mais limpa.
Analisa o conteudo do texto, faça os testes e mudanças necessarias e me envia um feedback.
Bons estudos.
Agora vai...!