Entity Framework - Usando entidades do EDM em uma aplicação WF
Neste artigo vamos por a mão na massa e trabalhar com as entidades do modelo de dados (EDM) gerados pelo Entity Framework (daqui para frente apenas EF) em uma aplicação Windows Forms. Nosso objetivo é mostrar como usar os objetos e os recursos do Entity Framework para acessar as entidades do EDM e efetuar as operações básicas relacionadas com as entidades como recuperação, alteração, inclusão e navegação.
Obs: Acompanhe a primeira parte do artigo em: Entity Framework - Usando o EF em uma aplicação Windows Forms I
Vamos iniciar definindo o nosso modelo de dados pois ele será o ponto de partida. Embora possamos trabalhar com o EF no sentido inverso , ou seja, definindo primeiro o modelo de classes e a partir dele gerar o modelo de dados, neste artigo eu vou partir de um modelo de dados pronto.
Vamos trabalhar com um banco de dados SQL Server chamado Editora.mdf que será composto pelas tabelas: Autor, Artigo e Pagamento;
Abaixo temos uma visão das tabelas e do diagrama do banco dados mostrando o relacionamento entre as tabelas:
Eu vou usar o Visual Studio 2008 SP1 para criar e gerenciar o exemplo deste artigo.
Inicie criando um novo projeto do tipo Windows Forms Application usando a linguagem Visual Basic com o nome EF_Editora;
Com o projeto criado podemos gerar o Entity Data Model-EDM a partir do banco de dados; O EDM será o objeto central a partir do qual iremos realizar todas as operações contra o banco de dados.
O Entity Data Model é um conceito, e
o Entity Framework possui uma implementação particular deste
modelo que é percebida como um arquivo EDMX em tempo de desenvolvimento.
Em tempo de execução o arquivo EDMX é
tratado em três arquivos XML separados cada um com um papel
definido:
|
Clique então com o botão direito do mouse sobre o projeto e selecione a opção Add New Item, e, a seguir selecione o template ADO .NET Entity Data Model, informe o nome Editora.edmx e clique no botão Add;
A seguir selecione a opção Generate from DataBase pois vamos gerar o modelo a partir do banco de dados Editora.mdf criado anteriormente. Clique em Next>;
A seguir selecione a conexão com o banco de dados Editora e aceite o nome para a entity connection que será salva no arquivo App.Config e clique em Next>;
Obs: Se a conexão ainda não foi criada clique no botão New Connection e selecione o servidor e o banco de dados para criar a conexão;
Selecione agora as tabelas que serão incluídas em nosso modelo e aceite o nome padrão EditoraModel e clique no botão Finish;
Depois de selecionar os objetos de banco de dados que desejamos incluir no modelo , o assistente do EDM gera o arquivo .edmx - Editora.edmx que define o modelo e o mapeamento e adiciona as referências ao projeto que são necessárias para o Entity Framework.
O arquivo .edmx é uma arquivo XML composto por quatro seções principais:
Abrindo o arquivo .edmx gerado iremos visualizar na representação gráfica do EDM as entidades criadas conforme a figura a seguir:
O descritor nos da uma visão geral do nosso modelo de entidades exibindo visualmente as entidades geradas a partir do modelo de banco de dados.(1)
Na janela Model Browser (2) podemos ver a estrutura completa do nosso projeto onde temos o modelo de entidades as associações e o modelo de banco de dados com as tabelas;
Na janela Mapping Details (3) vemos o mapeamento a nível de tabelas/entidades mostrando a correspondência campo = propriedade;
Na janela Properties (4) vemos o modelo conceitual gerado EditoraModel exibindo o nome do container e o nome do namespace adotado;
Nosso objetivo será gerenciar os dados da tabela Autor de forma que possamos exibir os registros em um formulário Windows Forms, efetuar a navegação pelos mesmos e realizar operações de alteração, inclusão e exclusão usando o modelo de entidades gerados pelo EF.
Vamos então definir o leiaute do formulário incluindo no formulário padrão form1.vb os controles :
O leiaute do formulário esta exibido a seguir:
Obs: Neste projeto temos um botão Enviar que é responsável por usar o método SaveChanges() do ObjectContext para persistir todas as atualizações para a fonte de dados e resetar as alterações no objectContext.
Antes de iniciar a criação do código devemos incluir uma referência ao namespace :
Imports
System.Data.ObjectsA seguir vamos declarar as variáveis que vamos usar no projeto:
Dim editoraContexto As EditoraEntitiesDefinimos aqui a variável editoraContexto do tipo EditoraEntities que representa o contexto do nosso modelo de entidades gerados pelo EF;
A variável autorLista representa uma lista de autores é e do tipo Autor;
A variável indiceAtual é do tipo integer e controla a posição atual;
As variáveis change e limpou são sinalizadores para verificarmos se houve alteração e se o botão limpar foi clicado;
Vamos começar incluindo o código a seguir no evento Load do formulário:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load editoraContexto = New EditoraEntities autorLista = New List(Of Autor) Dim autorConsulta As ObjectQuery(Of Autor) = editoraContexto.Autor.Where("it.Nome <> 'Mac'") autorLista = autorConsulta.ToList preencheCampos() End Sub |
Criei uma instância do objeto editoraContexto do tipo EditoraEntities que representa o nosso modelo de entidades e em seguida criei um novo objeto autorLista;
A seguir foi definida a consulta usando uma ADO .NET Entity Query Builder:
Dim autorConsulta As ObjectQuery(Of Autor) = editoraContexto.Autor.Where("it.Nome <> 'Mac'")
Métodos Query Builder - Permitem a construção de consultas Entity SQL usando vários métodos para filtrar dados usando o estilo de métodos de consulta LINQ;
O namespace System.Data.Objects é usado para criar e gerenciar objetos de entidades e o EF usa o ObjectQuery para construir e executar consultas que retornam objetos. Uma vez que um ObjectQuery tenha sido executado ele contém objetos tipados. |
A maioria das consultas Query Builder usam métodos de expressão (expression methods) que tem como resultado um ObjectQuery<>, ObjectResult<>, ou IQueryable<>, essas classes representam uma coleção de entidades retornadas pelas consultas. No nosso exemplo estamos usando um ObjectQuery(Of Autor) para obter uma coleção de objetos autores com exceção dos autores cujos nomes iniciam com a palavra Mac , ou seja vamos retornar todos os autores.
Através da aplicação dos Extensions Methods você pode, por exemplo, incluir funcionalidades adicionais a uma string sem ter que herdar da classe String, e o novo comportamento é tratado como um novo membro assim com os Extensions Methods é possível escrever um método que pode ser chamado como se ele fosse um método de instância de um tipo existente. fonte: VB.NET - Extensions Methods |
A Classe ObjectQuery(Of T) - Representa uma consulta contra o armazenamento no banco de dados e é formulada por meio de uma instrução de Entidade SQL , métodos de construtor de consultas ou Language-Integrated Query (LINQ).
A classe ObjectQuery representa uma consulta que retorna uma coleção objetos de entidades tipadas e sempre pertence a um contexto de objeto, no nosso caso ao contexto editoraContexto. Este contexto fornece a conexão e a informação necessária para compor e executar uma consulta e retorna uma instância tipada de ObjectQuery.
A classe ObjectQuery suporta tanto consultas LINQ to Entities como Entity SQL contra um Entity Data Model (EDM) e implementa um conjunto de métodos construtores que podem ser usados para construir comandos de consultas que são equivalentes aos métodos do Entity SQL.
A rotina preencheCampos() irá popular os controles de formulário exibindo os dados da entidade Autor. Seu código e dado abaixo:
Private Sub preencheCampos() Dim autorAtual As Autor = autorLista(indiceAtual) txtNome.Text = autorAtual.Nome txtSobrenome.Text = autorAtual.Sobrenome txtCodigoAutor.Text = autorAtual.AutorID.ToString End Sub |
Obtemos o objeto Autor atual da lista de objetos e atribuímos as propriedades mapeadas Nome , Sobrenome e AutorID aos controles de formulário.
A primeira execução do projeto irá exibir o seguinte resultado:
Para poder navegar pelos objetos vamos usar os eventos Click dos controles Buttons. Abaixo temos o código para cada um dos botões de comando:
Private Sub btnPrimeiro_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrimeiro.Click indiceAtual = 0 preencheCampos() End Sub Private Sub btnAnterior_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAnterior.Click If indiceAtual = 0 Then MessageBox.Show("Primeiro registro") Else indiceAtual -= 1 preencheCampos() End If End Sub Private Sub btnProximo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProximo.Click If (indiceAtual = autorLista.Count - 1) Then MessageBox.Show("Ultimo registro") preencheCampos() Else indiceAtual += 1 preencheCampos() End If End Sub Private Sub btnUltimo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUltimo.Click indiceAtual = autorLista.Count - 1 preencheCampos() End Sub |
Neste código estamos apenas tratando a variável indiceAtual que representa o índice atual do objeto na coleção de objetos e usando a rotina preencheCampos() para exibir os dados do objeto Autor atual no formulário.
Observe que a usamos a propriedade Count da coleção autorLista que obtém a quantidade de objetos na coleção.
Vejamos a seguir as demais funcionalidades implementadas para realizar as operações de incluir, alterar e excluir objetos.
Primeiro vamos ao código do botão Limpar que é usado para iniciar a inclusão de um novo objeto Autor no contexto.
Private Sub btnLimpar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLimpar.Click txtNome.Text = String.Empty txtSobrenome.Text = String.Empty txtCodigoAutor.Text = "Novo Autor" limpou = True End Sub |
A variável boolena limpou serve apenas para indicar se limpamos os controles; dessa forma se o usuário clicar no botão Novo sem limpar os controles e também sem informar valores para nome se sobrenome o usuário será alertado.
O código do botão Novo é exibido a seguir:
Private Sub btnNovo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNovo.Click If limpou And txtNome.Text <> String.Empty And txtSobrenome.Text <> String.Empty Then Dim novoAutor As New Autor novoAutor.Nome = txtNome.Text novoAutor.Sobrenome = txtSobrenome.Text novoAutor.AutorID = -1 autorLista.Add(novoAutor) editoraContexto.AddToAutor(novoAutor) indiceAtual = autorLista.Count - 1 preencheCampos() MsgBox("Um novo autor foi incluído, ENVIE no banco de dados") change = True limpou = False Else MsgBox("Para incluir um novo registro LIMPE os campos e informe novos dados.") End If End Sub
|
O código verifica se o botão Limpar foi acionado e se valores forma informados para em seguida criar uma nova instância da entidade Autor.
Em seguida atribuímos os valores informados no formulário ao objeto novoAutor e incluímos o novo objeto novoAutor na coleção de objetos : autorLista.Add(novoAutor)
Na linha de código editoraContexto.AddToAutor(novoAutor) o método AddTo<EntityName>, que é gerado pelo EF baseado nas entidades geradas a partir do banco de dados, irá realizar a inclusão do novo objeto no contexto.
Note que ainda não persistimos as alterações feitas no banco de dados. Isso é feito clicando no botão Enviar cujo código é dado a seguir:
Private Sub btnEnviar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEnviar.Click If change Then Dim registrosAfetados As Integer = editoraContexto.SaveChanges(True) MsgBox(registrosAfetados.ToString() + " alterações feitas") change = False preencheCampos() Else MsgBox("Não houve alteração") End If End Sub
|
Verificamos se houve alguma alteração e usamos o método SaveChanges() do contexto para persistir as alterações no banco de dados .
Para efetuar uma alteração , basta alterar a informação no formulário e clicar no botão Atualizar cujo código é o seguinte:
Private Sub btnAtualizar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAtualizar.Click Dim autorAtual As Autor = autorLista(indiceAtual) autorAtual.Nome = txtNome.Text autorAtual.Sobrenome = txtSobrenome.Text change = True End Sub |
O código obtém o objeto Autor atual e efetua as alterações. Para persistir devemos clicar no botão Enviar.
Finalmente o código do botão Excluir que é responsável por excluir um objeto Autor da coleção:
Private Sub btnExcluir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExcluir.Click If MsgBox("Confirma exclusão deste registros", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then 'obtem o autor atual Dim autorAtual As Autor = autorLista(indiceAtual) 'marca o objeto para ser excluído editoraContexto.DeleteObject(autorAtual) change = True autorAtual = Nothing End If End Sub
|
O método DeleteObject() marca o objeto para deleção a partir do ObjectStateManager, sendo que o objeto é efetivamente excluído quando o método SaveChanges é chamado.
Com isso mostrei uma outra forma de usar o EF para gerenciar os dados de um banco de dados SQL Server através das entidades mapeadas e geradas via EDM.
Pegue o projeto completo aqui : EF_Editora.zip
Eu sei é apenas Entity Framework, mas eu gosto...
Referências:
The Entity-RelationShip Model - Toward a Unified View of Data - http://csc.lsu.edu/news/erd.pdf - Peter Chen
Entity Framework - Usando o EF em uma aplicação Windows Forms I