Entity Framework 4.1 - Consultando entidades relacionadas (C#)


Neste artigo vou mostrar como podemos consultar entidades usando os recursos do Entity Framework 4.1.

Para o exemplo deste artigo vou usar o modelo de entidades gerado pelo Entity Data Model a partir do banco de dados Northwind.mdf.

O modelo de entidades foi gerado pelo assistente no formato de uma library chamada NorthwindEntities.dll que iremos referenciar em nosso projeto. Para saber como criar este modelo de entidades veja este artigo: EF 4.1 - Criando um Entity Data Model para uso em múltiplos projetos

Como já temos o nosso modelo de entidades pronto basta criar um projeto do tipo Windows Forms e mostrar como podemos realizar as consultas.

Apenas para conhecimento temos abaixo a figura exibindo o modelo de entidades gerado e que iremos usar no projeto:

Inicie o Visual C# 2010 Express Edition e crie um novo projeto do tipo Windows Forms Application com o nome ConsultandoEntidades;

A seguir vamos incluir no projeto as seguintes referências :

1- Incluindo uma referência ao Entity Framework 4.1 no nosso projeto;

- Clique com o botão direito do mouse sobre o projeto ConsultandoEntidades e clique em Add Reference;
- Na janela Add Reference clique na guia Browse e selecione o assembly EntityFramework.dll do local onde você instalou o Entity Framework 4.1 e clique em OK;

2- Incluindo uma referência ao modelo de entidades gerado pelo EDM no nosso projeto;

- Clique com o botão direito do mouse sobre o projeto ConsultandoEntidades e clique em Add Reference;
- Na janela Add Reference clique na guia Browse e selecione o assembly NorthwindEntities.dll do local onde você foi gerado o assembly (pasta bin do projeto) e clique em OK;

3- Incluindo uma referência ao namespace System.Data.Entity em nosso projeto;

- Clique com o botão direito do mouse sobre o projeto ConsultandoEntidades e clique em Add Reference;
- Na janela Add Reference clique na guia .NET e selecione o namespace System.Data.Entity e clique em OK;

Pronto ! Já temos o projeto e as referências necessárias agora vamos à luta...

Consultando entidades relacionadas no modelo

Abra o Visual C# 2010 Express Edition e crie um novo projeto do tipo Windows Application definindo no formulário form1.cs o leiaute conforme a figura abaixo:

Controles usados no formulário:
  • TabControl - tabcontrol1
  • Combobox - cboPedidos
  • Button - button1
  • DataGridView - dgvDetalhes
  • ListBox - lstDetalhes
  • Button - button3
  • ListBox - lstDetalhes1
  • DataGridView - dgvDetalhes2
  • Button - button4

Na carga do formulário vamos carregar o controle Combobox - cboPedidos - com as informações da tabela Orders.

Para isso vamos incluir o código abaixo no evento Load :

      private void Form1_Load(object sender, EventArgs e)
        {
            using (var contexto = new NorthwindEntities.NorthwindEntities())
            {
                //obtem os pedidos da entidade
             var pedidos = from p in contexto.Orders select p;
                //define o que será exibida na combo e valor de seleção e preenche o combobox
                cboPedidos.DisplayMember = "CustomerID";
                cboPedidos.ValueMember = "OrderID";
                cboPedidos.DataSource = pedidos.ToList();
            }
        }

No código acima estamos usando o contexto definindo no modelo de entidades para obter os dados dos pedidos e exibir o código do cliente no combobox;

A seguir temos o código onde obtemos o código do pedido selecionando na combobox e a seguir obtemos a lista de pedidos e dos detalhes dos pedidos para o pedido selecionado. Observe que usamos a função include para realizar o eager load explicitamente;

Na segunda consulta estamos obtendo o primeiro pedido e seu respectivo detalhe;

        private void button1_Click(object sender, EventArgs e)
        {
            using (var contexto = new NorthwindEntities.NorthwindEntities())
            {
                // obtem o número do pedido selecionado na combobox
                int orderid = Convert.ToInt32(cboPedidos.SelectedValue);
                // obtem a lista dos itens de pedidos para o pedido 
                var listaPedidos = (from p in contexto.Orders.Include("Order_Details") where p.OrderID == orderid select p).ToList();
                // obtem o primeiro iten de pedido para o pedido
                var primeiroPedido = (from p in contexto.Orders.Include("Order_Details") where p.OrderID == orderid select p).First();
                //exibe os itens dos pedidos
                dgvDetalhes.DataSource = listaPedidos;
                //exibe os detalhes dos primeiro pedido 
                lstDetalhes.Items.Add(primeiroPedido.OrderID);
                lstDetalhes.Items.Add(primeiroPedido.CustomerID);
                lstDetalhes.Items.Add(primeiroPedido.EmployeeID);
                lstDetalhes.Items.Add(primeiroPedido.OrderDate);
                lstDetalhes.Items.Add(primeiroPedido.RequiredDate);
                lstDetalhes.Items.Add(primeiroPedido.ShippedDate);
                lstDetalhes.Items.Add(primeiroPedido.ShipVia);
                lstDetalhes.Items.Add(primeiroPedido.Freight);
                lstDetalhes.Items.Add(primeiroPedido.ShipName);
                lstDetalhes.Items.Add(primeiroPedido.ShipAddress);
                lstDetalhes.Items.Add(primeiroPedido.ShipCity);
                lstDetalhes.Items.Add(primeiroPedido.ShipRegion == null ? "" : primeiroPedido.ShipRegion);
                lstDetalhes.Items.Add(primeiroPedido.ShipPostalCode);
                lstDetalhes.Items.Add(primeiroPedido.ShipCountry);
            }
        }

No código a seguir estamos desabilitando o lazy loading pois o padrão usado do Entity Framework é já vir com o lazy loading habilitado e para desabilitar você pode usar o seguinte comando:   seu_contexto.ContextOptions.LazyLoadingEnabled = false;

Dessa forma após realizar a consulta usando o código do cliente verificamos se os pedidos estão carregados(IsLoaded) se não estiverem usamos o método Load para carregar os pedidos para o cliente;

A seguir percorremos cada pedido verificando se os seus detalhes foram carregados para exibir os detalhes no controle ListBox:

        private void button3_Click(object sender, EventArgs e)
        {
            using (var contexto = new NorthwindEntities.NorthwindEntities())
            {
                contexto.ContextOptions.LazyLoadingEnabled = false;

                string codigo = cboPedidos.Text.Trim();
                lblCliente.Text = codigo;  
  
                var cliente = (from c in contexto.Customers where c.CustomerID == codigo select c).First();
                
                // Carrega os pedidos para o cliente selecionado
                if (!cliente.Orders.IsLoaded)
                {
                    cliente.Orders.Load();
                }

                foreach (Order pedido in cliente.Orders)
                {
                    // Carrega os itens para o pedido se não tiver ja carregado
                    if (!pedido.Order_Details.IsLoaded)
                    {
                        pedido.Order_Details.Load();
                    }
                    lstDetalhes1.Items.Add(String.Format("No. Pedido : {0}", pedido.OrderID));
                    lstDetalhes1.Items.Add(String.Format("Data Pedido: {0}", pedido.OrderDate.ToString()));

                foreach (Order_Detail item in pedido.Order_Details)
                {
                    //exibe os detalhes dos pedidos na listbox
                    lstDetalhes1.Items.Add(String.Format("Produto: {0} "
                        + "Qtde: {1}", item.ProductID.ToString(),item.Quantity.ToString()));
                }
              }
            }
        }

Temos aqui o que é conhecido como Lazy Load , ou em outras palavras : "se o programador não solicitar a carga, o relacionamento entre entidades não será recuperado."

Lazy Load é o mecanismo utilizado pelos frameworks de persistência para carregar informações sobre demanda. Esse mecanismo torna as entidades mais leves, pois suas associações são carregadas apenas no momento em que o método que disponibiliza o dado associativo é chamado. Assim quando objetos são retornados por uma consulta, os objetos relacionados não são carregados ao mesmo tempo, ao invés, eles são carregados automaticamente quando a propriedade de navegação for acessada.  É também conhecido como "lazy loading".

Você pode verificar se uma coleção de objetos está carregada utilizando a propriedade :  IsLoaded”. Para o nosso exemplo ficaria assim:

// Carrega os pedidos para o cliente selecionado
if (!cliente.Orders.IsLoaded)
 {
    cliente.Orders.Load();
 }

Uma outra forma de obter o mesmo resultado seria usar o que é conhecido como Eager Load.

Eager Load é o mecanismo pelo qual uma associação, coleção ou atributo é carregado imediatamente quando o objeto principal é carregado.

No Entity Framework o eager load é obtido explicitamente por meio da função Include

   private void button4_Click(object sender, EventArgs e)
        {
            using (var contexto = new NorthwindEntities.NorthwindEntities())
            {
                // obtem o número do pedido selecionado na combobox
                int orderid = Convert.ToInt32(cboPedidos.SelectedValue);
                var itenspedidos = (from p in contexto.Order_Details where p.OrderID == orderid select p).ToList();
                gdvDetalhes2.DataSource = itenspedidos;
            }
        }

Executando o projeto e realizando cada uma das consultas explanadas acima temos o seguinte resultado:

O EF 4.1 permite consultar o modelo de entidades de uma forma simples e eficaz como vimos acima. Mas isso é apenas o começo aguarde mais artigos sobre esse assunto em breve...

Pegue o projeto completo aqui: ConsultaEntidades.zip

"Como esta escrito: Não há um justo, nem um sequer. Não há ninguém que entenda; não há ninguém que busque a Deus." Rom. 10-11

Referências:


José Carlos Macoratti