Entity Framework 4 - Operações básicas de acesso a dados - 2


Na primeira parte deste artigo apresentei os objetivos e criei toda a infra-estrutura para que possamos nesta segunda parte ir ao que interessa. Eu realizei uma pequena alteração a interface apresentada na primeira parte para tornar mais intuitiva a interação com usuário dessa forma eu incluir um formulário MDI que será o formulário principal e no formulário de vendas eu incluir um controle TabControl com duas abas :

Ficou assim:

Vamos agora continuar focando o formulário de registro de pedidos onde iremos usar os recursos do Entity Framework(EF) para acessar e persistir as informações na nossa base de dados usando as entidades do modelo de entidades criado pelo Entity Data Model(EDM).

Ao carregar e aplicação e chamar o formulário de Vendas temos o seguinte resultado:

Note que :

- No controle ListBox estão sendo exibidos os clientes cadastrados;
- O controle ComboBox exibe os produtos cadastrados;

Vejamos como acessar essa informações e preencher estes controles usando Entity Framework.

Para começar no início do formulário iremos definir a referência ao projeto Persistencia;

using Persistencia;

A seguir vamos definir a variável ctx do tipo ObjecContext, nosso caso o ObjectContext possui o nome JcmSoftEntities.

Definirmos também duas variáveis para controlar o código do produto e do cliente;

JcmSoftEntities ctx = null;
int idProduto;
int idCliente;

Para preencher os controles listbox1 e combobox1 (eu estou usando os nomes padrões mas recomendo que você use nomes próprios) vamos usar o evento Load do formulário definindo nele o seguinte código:

  private void Form1_Load(object sender, EventArgs e)
  {
            ctx = new JcmSoftEntities();
            comboBox1.DisplayMember ="nome";     //selecteditem
            comboBox1.ValueMember = "produtoid"; //selectedvalue
            comboBox1.DataSource = ctx.Produtos; 
            listBox1.DataSource = ctx.Clientes;  
            listBox1.DisplayMember = "nome";
            listBox1.ValueMember = "clienteid";
            //dataGridView1.DataSource = ctx.Detalhes;
  }

No código acima primeiro criarmos uma instância do nosso Contexto representado por JcmSoftEntities, é através do contexto que teremos acesso as entidades e aos seus métodos e poderemos também persistir as informações nos objetos e na base de dados.

A seguir usei a propriedade DisplayMember e ValueMember dos controles para definir o que será exibido no controle , em ambos os casos a propriedade nome, e também o valor que será usado quando um item for selecionado do controle, no caso o código do produto e do cliente.

A propriedade DataSource define a fonte das informações no caso as entidades Produtos e Clientes do Contexto.

Nota:  O código comentado : dataGridView1.DataSource = ctx.Detalhes permite exibir os detalhes dos pedidos dos clientes no controle dataGridView1 da aba Pedidos - Cliente.

Notou que não precisamos nos preocupar em definir os objetos para conexão nem os objetos como dataadpater, dataset, datareader e nem comandos SQL. Graças ao Entity Framework.

Para definir o pedido devemos selecionar um cliente e um produto e ao fazer essa seleção teremos os demais controles do formulário preenchidos. Assim ao selecionar um cliente os controles TextBox Nome e Endereço são preenchidos com informações do cliente.

Da mesma forma ao selecionar um produto o seu preço será preenchido no controle TextBox.

Fazemos isso usando o evento SelectedIndexChanged dos controles ListBox e Combobox. Neste evento temos o seguinte código:

  private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
   {
            if (int.TryParse(listBox1.SelectedValue.ToString(), out idCliente))
            {
                using (var ctx = new JcmSoftEntities())
                {
                    var cliente = ctx.Clientes.First(c => c.clienteid == idCliente);
                    txtNomeCliente.Text = cliente.nome;
                    txtEnderecoCliente.Text = cliente.endereco;
                }
            }
        }

 

 private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (int.TryParse(comboBox1.SelectedValue.ToString(), out idProduto))
            {
                using (var ctx = new JcmSoftEntities())
                {
                    var produto = ctx.Produtos.First(p => p.produtoid == idProduto);
                    txtPrecoProduto.Text = String.Format("{0:#,###.##}", produto.preco.ToString());
                }
            }
        }			

ListBox - Clientes

ComboBox - Produtos

O código é idêntico e nele primeiro obtemos o id do cliente e do produto selecionado e depois efetuamos uma busca pelo cliente/produto :

 var cliente = ctx.Clientes.First(c => c.clienteid == idCliente);
 var produto = ctx.Produtos.First(p => p.produtoid == idProduto);

Nesta consulta LINQ estamos usando o  operador First que retorna o primeiro elemento da seqüência que satisfaz o critério definido na expressão lambda;

O que são Expressões Lambda ?

As expressões lambda foram incluídas no VS/VB 2008/C# para dar suporte a consultas LINQ. As cláusulas Where são assim compiladas como expressões lambdas e chamadas em itens aplicáveis do seu dataset. Podem ser consideradas uma forma de delegate que pode passar ou retornar outra função.

Nota: Delegates permitem que uma classe use métodos de outra classe. Para saber mais sobre delegates leia o meu artigo: Usando Delegates

No LINQ as expressões lambda são usadas para realizar ações sobre listas de objetos e com métodos de extensão.
Uma expressão lambda é então uma função sem nome que calcula e retorna um valor único e podem ser usadas em qualquer lugar que um tipo delegate for válido.

A seguir exibimos as respectivas informações nos controles TextBox do formulário.

Após selecionar o cliente e o produto basta informar a quantidade e a data do pedido basta clicar no botão - Confirmar Pedido - para persistir as informações do pedido nas entidades.

Para isso usamos o evento Click do botão inserindo nele o seguinte código:

    private void btnConfirmarPedido_Click(object sender, EventArgs e)
        {
            if (!nupdQuantidade.Text.Equals("") || !dtpDataPedido.Value.Equals("") || txtNomeCliente.Text.Equals(""))
            {
                Pedido pedido = new Pedido();
                pedido.clienteid = idCliente;
                pedido.datapedido = Convert.ToDateTime(dtpDataPedido.Value);

                ctx.AddToPedidos(pedido);
                Detalhe detalhe = new Detalhe();
                detalhe.produtoid = idProduto;
                detalhe.preco = Convert.ToDecimal(txtPrecoProduto.Text);
                detalhe.quantidade = Convert.ToInt32(nupdQuantidade.Text);
                detalhe.Pedido = pedido;
                AtualizaEstoque(detalhe);
                try
                {
                    ctx.SaveChanges();
                    MessageBox.Show("Pedidos Gravado com sucesso.");
                }
                catch( Exception ex )
                {
                    MessageBox.Show("Erro : " + ex.InnerException.ToString());
                }
            }
            else
            {
                MessageBox.Show("Dados inválidos.");
            }
        }

Vamos entender o que este código faz:

- Primeiro verificamos se foi informada a quantidade, a data do pedido e se um cliente foi selecionado;

- Em seguida criamos um instância da entidade Pedido() e atribuímos os valores do id do cliente selecionado e da data do pedido informada as propriedades clienteid e datapedido da entidade;

- Depois usamos o método AddToPedidos para incluir o novo objeto Pedido na coleção de objetos: ctx.AddToPedidos(pedido);

Você pode incluir novos objetos a um contexto de objeto através do método AddObject ou chamando um dos métodos AddToEntitySetName do ObjectConext.
Você também pode incluir um objeto a um contexto de objeto adicionando o objeto a um EntityCollection existente.
Quando você chama o método Add em um EntityCollection que esta anexada a um contexto de objeto , o objeto que você esta incluindo é adicionado ao mesmo ObjectContext.

Na linha de código  ctx.AddToPedidos(pedido) o método AddTo<EntityName>,  que é usado pelo EF baseado nas entidades geradas a partir do banco de dados,e , irá realizar a inclusão do novo objeto no contexto.

Repetimos a operação para a entidade Detalhe definindo os valores do id do produto , preço e quantidade e a seguir atribuímos o pedido criado ao detalhe do pedido:  detalhe.Pedido = pedido;

Antes de persistimos as informações chamamos o método  AtualizaEstoque(detalhe); que irá atualizar o estoque do produto que foi vendido.

Este método possui o seguinte código:

  private void AtualizaEstoque(Detalhe detalhe)
  {
            var produto = ctx.Produtos.First(p => p.produtoid == detalhe.produtoid);
            int quantidadePedido = Convert.ToInt32(detalhe.quantidade);
            int estoqueProduto = Convert.ToInt32(produto.estoque);
            produto.estoque = estoqueProduto - quantidadePedido;

            ctx.Produtos.ApplyCurrentValues(produto);
  }

Observe que neste código procuramos pelo produto que esta sendo feito o pedido usando uma consulta LINQ com operador First e expressão lambda;

Em seguida atualizamos o estoque subtraindo a quantidade do pedido do estoque do produto.

Para podermos persistir esta informação na entidade usamos o método ApplyCurrentValues(produto);

O método ApplyCurrentValues(TEntity) copia os valores escalares a partir do objeto fornecido para o objeto no ObjectContext que possui a mesma chave.

Este método é usado para aplicar as mudanças que foram feitas a objetos fora do ObjectContext, tais como um objeto desanexado (detached) que são recebidos por um web service. (Você pode usar o EntityKey do objeto detached para retornar uma instância deste objeto a partir da fonte de dados.)

Após isso usamos o  método SaveChanges() do contexto para persistir as alterações nas entidades e replicar no banco de dados.

Para encerrar preciso falar sobre a exibição dos detalhes do pedido na aba - Pedidos - Cliente.

Ao clicar no botão - Mostra Pedidos - no evento Click deste botão temos o seguinte código:

    private void btnMostraPedidos_Click(object sender, EventArgs e)
    {
            tabVendas.SelectTab("tabPage2");
            MostraPedidosCliente();
   }

Primeiro selecionamos e ativamos aba - tabPage2 - que é a aba Pedidos - Cliente;

Em seguida chamamos o método MostraPedidosCliente() que possui o seguinte código:

   private void MostraPedidosCliente()
        {
            var consulta = from dep in ctx.Detalhes.Include("Produtos")
                                 where dep.Pedido.clienteid == idCliente
                                 select new
                                {
                                    dep.Produto.nome,
                                    dep.quantidade,
                                    dep.preco,
                                    dep.Pedido.datapedido
                                };
                          
            dataGridView1.DataSource = consulta.ToList();
            dataGridView1.Refresh();
        }

 

Este método realiza uma consulta LINQ onde selecionamos os detalhes de um pedido para o cliente selecionado (idCliente) e em seguida exibe o resultado no controle DataGridView.

Como você pode acompanhar realizar tarefas básicas mas de rotina em aplicações com acesso a dados de uma forma bem simples usando um código enxuto e deixando todo o trabalho de para o Entity Framework. Tivemos somente o trabalho de prepará-lo para ser usado com o modelo de dados do projeto.

Esse um dos muitos motivos para considerar a utilização do Entity Framework em suas aplicações de acesso a dados. É claro que nem sempre ele será a opção mais recomendada pois cada projeto tem suas características e particularidades mas é muito importante você conhecer como ele funciona para poder tomar essa decisão.

Pegue o projeto completo aqui: ef4_Operacoes_BD.zip

Eu sei é apenas Entity Framework mas eu gosto...

Referências:


José Carlos Macoratti