none
JOIN duas vezes com Entity RRS feed

  • Pergunta

  • Tenho classes Cidade, Estado e Pais.    Uma CIDADE tem um ESTADO e um ESTADO tem um PAIS.

    Comprei um livro de Entity Framework para aprofundar e estou fazendo uns testes.  Aprendi a pegar o SQL gerado e verifiquei que em uma consulta ele está fazendo JOIN duas vezes.

    Vejam as classes:

    [Table("pais")]
        public class Pais
        {
            [Key]
            [Column("pai_codigo")]
            public int Codigo { get; set; }
    
            [Required]
            [Column("pai_nome")]
            public string Nome { get; set; }
    
            [Column("pai_sigla")]
            public string Sigla { get; set; }
    
            [Column("pai_codigoIBGE")]
            public string CodigoIBGE { get; set; }
    
            [Column("pai_sigla2")]
            public string Sigla2 { get; set; }
    
            [Column("pai_codigogeral")]
            public Int16 CodigoGeral { get; set; }
        }


    [Table("estado")]
        public class Estado
        {
            [Key]
            [Column("est_codigo")]
            public int Codigo { get; set; }
    
            [Required]
            [Column("est_nome")]
            public string Nome { get; set; }
    
            [Column("est_sigla")]
            public string Sigla { get; set; }
    
            [Column("est_codigoIBGE")]
            public string CodigoIBGE { get; set; }
    
            [Column("est_pais")]
            public int CodigoPais { get; set; }
    
            [ForeignKey("CodigoPais")]
            public virtual Pais Pais { get; set; }
        }


    [Table("cidade")]
        public class Cidade
        {
            [Key]
            [Column("cid_codigo")]
            public int Codigo { get; set; }
    
            [Required]
            [Column("cid_nome")]
            public string Nome { get; set; }
            
            [Column("cid_codigoIBGE")]
            public string CodigoIBGE { get; set; }
    
            [Column("cid_estado")]
            public int CodigoEstado { get; set; }
    
            [ForeignKey("CodigoEstado")]
            public virtual Estado Estado { get; set; }
        }

    Até aí eu acho que não tem problemas, segui tudo conforme foi falado.

    Para um teste simples eu fiz a seguinte consulta LINQ no EF:

    var Data =          from o in Ctx.DbCidade
                                            select new {o.Nome, Estado = o.Estado.Nome, Pais = o.Estado.Pais.Nome };

    O resultado vem corretamente, mas na hora que eu fui verificar o SQL gerado ele fez o seguinte:

    SELECT 
    [Extent1].[cid_estado] AS [cid_estado], 
    [Extent1].[cid_nome] AS [cid_nome], 
    [Extent2].[est_nome] AS [est_nome], 
    [Extent4].[pai_nome] AS [pai_nome]
    FROM    [dbo].[cidade] AS [Extent1]
    INNER JOIN [dbo].[estado] AS [Extent2] ON [Extent1].[cid_estado] = [Extent2].[est_codigo]
    LEFT OUTER JOIN [dbo].[estado] AS [Extent3] ON [Extent1].[cid_estado] = [Extent3].[est_codigo]
    LEFT OUTER JOIN [dbo].[pais] AS [Extent4] ON [Extent3].[est_pais] = [Extent4].[pai_codigo]

    Bom reverifiquei tudo e não entendi o motivo dele fazer INNER JOIN com ESTADO e depois fazer um LEFT OUTER JOIN com estado novamente.

    Alguém pode me ajudar? Obrigado!

    terça-feira, 12 de fevereiro de 2013 23:15

Respostas

  • O EF vai criar automaticamente esta tabela e ai você pode acessar desta forma:

    Pegar todas as empresas do usuário:

    public class Usuario{
        public int Id{get;set;}
        public List<Empresa> Empresas{get;set;}
    }
    
    var user = db.Usuario.Find(1);
    var empresas = user.Empresas;

    Pegar todos os usuários de uma empresa:

    public class Empresa{
        public int Id{get;set;}
        public List<Usuario> Usuarios{get;set;}
    }
    
    var empresa = db.Empresa.Find(1);
    var usuarios = empresa.Usuarios;


    http://www.linkedin.com/pub/murilo-kunze/44/191/455

    quarta-feira, 13 de fevereiro de 2013 11:34

Todas as Respostas

  • Qual versão do entity você está usando?

    Se eu não me engano a partir da versão 4 ou 5 algumas querys foram otimizadas.


    http://www.linkedin.com/pub/murilo-kunze/44/191/455

    terça-feira, 12 de fevereiro de 2013 23:28
  • Acho que é a versão 4.  Vou confirmar.  

    Bom pelo menos então não há erro nas classes?  Então tá show!!

    Murilo outra dúvida, talvez você possa responder.   Comprei o livro de EF e ele ensina a fazer via EDMX e não data annotations.   Daí por exemplo tenho tabela USUARIO e EMPRESA.  Daí preciso controlar quais empresas o usuário tem permissão para utilização.    No EDMX ele não indica, pelo menos no livro, criar uma classe para a tabela USUARIO_EMPRESA, ele deixa isso como um relacionamento entre as classes e coloca uma propriedade de navegação em cada entidade relacionada a outra.

    Via data annotation eu não vejo como não ser assim.  Eu crio uma classe UsuarioEmpresa e coloco uma propriedade Usuario e outra Empresa nela.

    Estou no caminho certo?

    quarta-feira, 13 de fevereiro de 2013 10:48
  • Neste caso você não precisa criar a tabela do meio, basta criar as propriedades de navegação em cada ponta.

    http://www.linkedin.com/pub/murilo-kunze/44/191/455

    quarta-feira, 13 de fevereiro de 2013 10:52
  • Mas não vejo como especificar qual tabela e campos certinhos o EF irá usar.  Em resumo seria:

    USUARIO
    usu_codigo

    EMPRESA
    emp_codigo

    USUARIOEMPRESA
    uem_codigo (sequencial)
    uem_usuario
    uem_empresa

    Se não por este cara em uma entidade especifica como o EF vai chamar ele certinho?

    quarta-feira, 13 de fevereiro de 2013 11:29
  • O EF vai criar automaticamente esta tabela e ai você pode acessar desta forma:

    Pegar todas as empresas do usuário:

    public class Usuario{
        public int Id{get;set;}
        public List<Empresa> Empresas{get;set;}
    }
    
    var user = db.Usuario.Find(1);
    var empresas = user.Empresas;

    Pegar todos os usuários de uma empresa:

    public class Empresa{
        public int Id{get;set;}
        public List<Usuario> Usuarios{get;set;}
    }
    
    var empresa = db.Empresa.Find(1);
    var usuarios = empresa.Usuarios;


    http://www.linkedin.com/pub/murilo-kunze/44/191/455

    quarta-feira, 13 de fevereiro de 2013 11:34
  • Entendi.. porém: minha estrutura está toda pronta da forma que falei. Daí acho que preciso de uma entidade mesmo.

    quarta-feira, 13 de fevereiro de 2013 12:09
  • Sua entity Usuario não possui uma List<Empresas>??

    http://www.linkedin.com/pub/murilo-kunze/44/191/455

    quarta-feira, 13 de fevereiro de 2013 12:13
  • Estou tentando criar mas é baseada numa base já existente e em utilização.  Na verdade nem tentei pra ver o que vai dar, estou antecipando já que existe uma tabela pre existente e com nomes de campos no meu padrao, nada de Id tal

    quarta-feira, 13 de fevereiro de 2013 12:21