none
Entity Framework, Consulta com 2 ou mais joins usando expressão Lambda RRS feed

  • Pergunta

  • Pessoal como que se faz pra realizar uma consulta no banco de dados usando expressões Lambda e dois ou mais Joins?

    Eu consigo fazer usando o Linq dessa maneira:

    var relatorio = (from c in Cnoperacao.tb_operacao_calltype
                             join r1 in Cnoperacao.tb_operacao_calltype_reason1 on c.id_reason1 equals r1.cod_reason into c_r1
                             join r2 in Cnoperacao.tb_operacao_calltype_reason2 on c.id_reason2 equals r2.cod_reason into c_r2
                             where c.data >= datainicial && c.data <= datafinal
                                 from r1 in c_r1.DefaultIfEmpty()
                                 from r2 in c_r2.DefaultIfEmpty()
                             select new {
                                 Data = c.data,
                                 Reason1 = r1.nm_reason== null ? "-" : r1.nm_reason,
                                 Reason2 = r2.nm_reason== null ? "-" : r2.nm_reason}).ToList();

    Eu queria aprender como fazer essa consulta usando expressões Lambda, com um join eu até consegui, confesso que não entendi muito bem, mas com dois ou mais joins não achei nada que explicasse.

    Alguém poderia me ajudar?

    terça-feira, 25 de fevereiro de 2014 22:14

Respostas

  • GroupJoin 

    var groupJoin =
        db.Produto
        .GroupJoin(db.Categoria, pr => pr.CategoriaId, ca => ca.Id, (pr, ca) => new { pr, ca })
        .GroupJoin(db.Tipo, pr => pr.pr.TipoId, ti => ti.Id, (pr, ti) => new { pr, ti })
        .SelectMany(temp => temp.ti.DefaultIfEmpty(), (pr, ca) => new { pr, ca })
        .SelectMany(temp => temp.pr.pr.ca.DefaultIfEmpty(), (a, b) => new
        {
            CatId = a.pr.pr.pr.CategoriaId,
            CatNome = a.pr.pr.pr.Categoria.Nome,
            TipId = a.pr.pr.pr.TipoId,
            TipNome = a.pr.pr.pr.Tipo.TipoDescricao,
            ProId = a.pr.pr.pr.Id,
            ProNome = a.pr.pr.pr.Descricao
        }).AsQueryable();

    é bem parecido mas, utilize o GroupJoin com SelectMany para fazer esse tipo de agregação!

    Só dará certo o LetJoin (porque o framework analisa se realmente tem as condições para realizar tal SQL)

    é a mesma coisa mas, vai ter que mudar na parte do SelectMany !!!

    Exemplo simples no meu Blog: 

    http://fulviocanducci.wordpress.com/2013/12/06/entity-framework-inner-join-e-left-join-lambda-expression/


    Fulvio Cezar Canducci Dias


    quarta-feira, 26 de fevereiro de 2014 14:29

Todas as Respostas

  • Realmente !!! é bem dificil de encontrar  !!!

    Vamos lá!

    Nesse modelo acima perceba que a Tabela Produtos tem 2 Relacionamentos de Tipo e Categoria, para que eu pegue a descrição dessas tabelas precisamos de Joins !!!

    Em Lambda seria:

    using (AppDbEntities db = new AppDbEntities())
    {
    	var Joins =
    		db.Produto
    		.Join(db.Tipo, pr => pr.TipoId, ti => ti.Id, (pr, ti) => new { pr, ti })
    		.Join(db.Categoria, pr1 => pr1.pr.CategoriaId, ca => ca.Id, (pr1, ca) => new { pr1, ca })
    		.Select(x => new
    		{
    			CategoriaId = x.ca.Id, 
    			CategoriaNome = x.ca.Nome, 
    			TipoId = x.pr1.ti.Id,
    			TipoNome = x.pr1.ti.TipoDescricao,
    			ProdutoId = x.pr1.pr.Id, 
    			ProdutoDescricao = x.pr1.pr.Descricao
    		}).AsQueryable();
    
    	var Results = Joins.ToArray();
    }

    Perceba que quanto mais Joins mais complicado fica mas, é assim que funciona ...

    SQL Gerada! (Importante)

    SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent3].[Id] AS [Id1], 
        [Extent3].[Nome] AS [Nome], 
        [Extent2].[Id] AS [Id2], 
        [Extent2].[TipoDescricao] AS [TipoDescricao], 
        [Extent1].[Descricao] AS [Descricao]
        FROM   [dbo].[Produto] AS [Extent1]
        INNER JOIN [dbo].[Tipo] AS [Extent2] ON [Extent1].[TipoId] = [Extent2].[Id]
        INNER JOIN [dbo].[Categoria] AS [Extent3] ON [Extent1].[CategoriaId] = [Extent3].[Id]

    Perceba que tem alguns comando do proprio Framework ORM, mas, ele faz o Joins corretamente !!!


    Fulvio Cezar Canducci Dias

    terça-feira, 25 de fevereiro de 2014 22:15
  • Obrigado Fúlvio foi de grane ajuda, pois acho que entendi como funciona a lógica porém eu tenho o seguinte cenáiro:

    var relatorio = Cnoperacao.tb_operacao_calltype
    .Join(Cnoperacao.tb_operacao_calltype_reason1, c => c.id_reason1, r1 => r1.cod_reason, (c, r1) => new { c, r1 })
    .Join(Cnoperacao.tb_operacao_calltype_reason2, c1 => c1.c.id_reason2, r2 => r2.cod_reason, (c1, r2) => new { c1, r2 })
    .Join(Cnoperacao.tb_operacao_calltype_reason3, c2 => c2.c1.c.id_reason3, r3 => r3.cod_reason, (c2, r3) => new { c2, r3 })
    .Join(Cnoperacao.tb_operacao_familia, c3 => c3.c2.c1.c.id_familia, f => f.cod_familia, (c3, f) => new { c3, f })
    .Join(Cnoperacao.tb_operacao_produto, c4 => c4.c3.c2.c1.c.id_produto, p => p.cod_produto, (c4, p) => new { c4, p })
    .Join(Cnoperacao.tb_operacao_calltype_setor, c5=>c5.c4.c3.c2.c1.c.id_setor,s=>s.cod_setor,(c5,s)=>new{c5,s})
    .Where(x => x.c5.c4.c3.c2.c1.c.data >= datainicial && x.c5.c4.c3.c2.c1.c.data<=datafinal)
    .Select(x => new{
    ID = x.c5.c4.c3.c2.c1.c.cod_call_type,
    Data = x.c5.c4.c3.c2.c1.c.data,
    NR_Chamado = x.c5.c4.c3.c2.c1.c.nr_chamado,
    Reason1 = x.c5.c4.c3.c2.c1.r1.nm_reason,
    Reason2 = x.c5.c4.c3.c2.r2.nm_reason,
    Reason3 = x.c5.c4.c3.r3.nm_reason,
    Familia = x.c5.c4.f.nm_familia,
    Produto = x.c5.p.nm_produto,
    Primeiro_Contato = x.c5.c4.c3.c2.c1.c.ds_primeiroContato,
    Setor = x.s.nm_setor}).ToList();

    Tenho 6 tabelas de relacionamento para este sistema, consegui fazer da maneira acima, porém acontece que em alguns casos o campo Reason3 e Setor serão nulos, e fazendo desta forma o inner join não traz a linha que tenha algum campo nulo. 

    Como se faz um Left Join pra poder retornar todas as linhas com campos nulos ou não?

    quarta-feira, 26 de fevereiro de 2014 14:08
  • GroupJoin 

    var groupJoin =
        db.Produto
        .GroupJoin(db.Categoria, pr => pr.CategoriaId, ca => ca.Id, (pr, ca) => new { pr, ca })
        .GroupJoin(db.Tipo, pr => pr.pr.TipoId, ti => ti.Id, (pr, ti) => new { pr, ti })
        .SelectMany(temp => temp.ti.DefaultIfEmpty(), (pr, ca) => new { pr, ca })
        .SelectMany(temp => temp.pr.pr.ca.DefaultIfEmpty(), (a, b) => new
        {
            CatId = a.pr.pr.pr.CategoriaId,
            CatNome = a.pr.pr.pr.Categoria.Nome,
            TipId = a.pr.pr.pr.TipoId,
            TipNome = a.pr.pr.pr.Tipo.TipoDescricao,
            ProId = a.pr.pr.pr.Id,
            ProNome = a.pr.pr.pr.Descricao
        }).AsQueryable();

    é bem parecido mas, utilize o GroupJoin com SelectMany para fazer esse tipo de agregação!

    Só dará certo o LetJoin (porque o framework analisa se realmente tem as condições para realizar tal SQL)

    é a mesma coisa mas, vai ter que mudar na parte do SelectMany !!!

    Exemplo simples no meu Blog: 

    http://fulviocanducci.wordpress.com/2013/12/06/entity-framework-inner-join-e-left-join-lambda-expression/


    Fulvio Cezar Canducci Dias


    quarta-feira, 26 de fevereiro de 2014 14:29
  • Muito Obrigado.

    Consegui fazer funcionar, ficou enorme mas eu consegui entender a sintaxe e funcionou perfeitamente.

    quarta-feira, 26 de fevereiro de 2014 14:58