13
respostas

Problemas no ThenInclude

      var query = contexto
                    .Promocoes
                    //produtos está relacionado a promocao produto como ilist
                    .Include(p => p.Produtos)
                    .ThenInclude(pp => pp.);

Boa dia, estou tentando utilizar o thenInclude, mas quando passo a funcao lambda ele não mostra nenhuma propriedade. Copiei o exemplo do curso mesmo assim não mostra a propriedade produto. As unicas propriedade são count e isreadonly

13 respostas

Desculpe-me por mais essa pergunta, mas teria como fazer a mesma consulta utilizando linQ ao invés de lambda? agradeço a ajuda de vcs

Vladmir, tudo bem?

Você pode colocar aqui o código das suas classes Produto e Promocao, além da declaração da classe de contexto?

opa, beleza professor!!


namespace LojaNovo
{
    public class Produto
    {
        public int Id { get; set; }
        public string Categoria { get; set; }
        public string Nome { get; set; }
        public double PrecoUnitario { get; set; }
        public string Unidade { get; set; }
        public IList<PromocaoProduto> Promocoes { get; set; }
    }
}

namespace LojaNovo
{
    public class Promocao
    {
        public int Id { get; set; }
        public string Descricao { get; internal set; }
        public DateTime DataInicio { get; internal set; }
        public DateTime DataTermino { get; internal set; }
        public IList<PromocaoProduto> Produtos { get; internal set; }

        public Promocao()
        {
            Produtos = new List<PromocaoProduto>();
        }

        public void IncluiProduto(Produto produto)
        {
            //
            var p = new PromocaoProduto();
            p.Produto = produto;
            Produtos.Add(p);
        }
    }
}

using Microsoft.EntityFrameworkCore;
using System;

namespace LojaNovo
{
    internal class LojaContext : DbContext
    {
        public DbSet<Produto> Produtos { get; set; }
        public DbSet<Compra> Compras { get; set; }
        public DbSet<Promocao> Promocoes { get; set; }
        public DbSet<Cliente> Clientes { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=LojaDB;Trusted_Connection=true;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.
                Entity<PromocaoProduto>().
                HasKey(p => new { p.PromocaoId, p.ProdutoId });

            modelBuilder.
                Entity<Endereco>().
                Property<int>("ClienteId");

            modelBuilder.
                Entity<Endereco>().
                HasKey("ClienteId");

            modelBuilder.
                Entity<Endereco>().
                ToTable("Enderecos");
            //base.OnModelCreating(modelBuilder);
        }
    }

}

Vladmir, faltou a classe PromocaoProduto que é aquela que faz o relacionamento entre promoções e produtos. Serão suas propriedades que aparecerão na expressão lambda do método ThenInclude().

professor tambem fiz

using System;

namespace Alura.Loja.Testes.ConsoleApp
{
    public class PromocaoProduto
    {
        public int ProdutoId { get; set; }
        public int PromocaoId { get; set; }
        public Produto Produto { get; set; }
        public Promocao Promocao { get; set; }
    }
}

o que será que está errado?

Vladmir, seu código está certinho.

Testei ele aqui em minha máquina e está tudo ok. Veja:

static void Main(string[] args)
{
    using (var ctx = new LojaContext())
    {
        var query = ctx
            .Promocoes
            .Include(p => p.Produtos)
            .ThenInclude(pp => pp.Produto)
            .FirstOrDefault();
    }
}

Se não estiver aparecendo a propriedade Produto não tema! Escreva-a e finalize com o método FirstOrDefault().

Tambem tentei montar deste jeito, mas deu erro

                var query2 = from prom in contexto.Promocoes
                             join prod in contexto.Produtos
                             on prom.Produtos equals prod.Promocoes
                             select new
                             {
                                 nome = prom.Descricao,
                                 produtos = prod.Nome
                             };

Tentei isso na classe program e aparece o seguinte erro na query do foreach "instrucoes foreach nao podem operar em variaveis do tipo promocao porque promocao nao contem uma definicao publica para getEnumerator"

    class Program
    {
        static void Main(string[] args)
        {
            using (var contexto = new LojaContext())
            {
                var query2 = from prom in contexto.Promocoes
                             join prod in contexto.Produtos
                             on prom.Produtos equals prod.Promocoes
                             select new
                             {
                                 nome = prom.Descricao,
                                 produtos = prod.Nome
                             };

                var query = contexto
                    .Promocoes.Include(p => p.Produtos)
                    .FirstOrDefault();
                foreach (var item in query)
                {
                    Console.WriteLine($" {item.nome} {item.nomePromocao}");
                }

                Console.ReadKey();
            }
        }

Vamos às suas duas dúvidas.

Consulta usando LINQ

Para fazer a consulta usando LINQ faça assim:

static void Main(string[] args)
{
    using (var ctx = new LojaContext())
    {
        var produtos = from promocao in ctx.Promocoes
                    from pp in promocao.Produtos
                    select new { promocao.Descricao, pp.Produto.Nome };

        foreach (var p in produtos)
        {
            Console.WriteLine($"{p.Descricao} - {p.Nome}");
        }

    }
}

Erro no foreach

O erro do foreach acontece porque finalizamos a consulta com o método FirstOrDefault() que só retorna um elemento do SELECT: o primeiro, que no exemplo é uma instância de promoção (o EF Core internamente monta o SQL usando SELECT TOP 1).

Não dá pra fazermos um foreach em uma promoção. Se quiser retornar mais de um registro da tabela de promoções substitua FirstOrDefault() por ToList().

Espero que tenha ajudado!

Professor muito obrigado pela atenção prestada!!! Esta funcionando graças a sua paciencia, mas só mais uma informação no select vc colocou 2 from como o entity sabe em quem ligar sem o on equals e onde posso aprender mais sobre o assunto Assisti sua aula de linQ e lambda agradeço novamente as informaçoes!!! nota 10

Vladmir, fico feliz que conseguiu fazer funcionar. Sua dedicação e determinação foram muito importantes. Continue com essas atitudes!

Sobre a questão do from usado 2 vezes: o EF só sabe fazer o join porque nós escrevemos o segundo from usando a propriedade Produtos da instância de promocao e não do contexto. Repare nisso.

Sobre referências para você estudar, confesso que uso bastante o google pra saber sintaxe e uso do LINQ. O StackOverflow também. Uma referência mais estruturada é esse link aqui:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/join-clause

Espero que tenha ajudado. Boas aulas!

valeu professor, ajudou muito!!