Entity Framework -  conceitos básicos : Incluindo, modificando e excluindo objetos II


Este série de artigos é dedicada ao Entity Framework e tem o objetivo de dar uma introdução básica e uma visão geral de como usar este importante recurso da plataforma .NET. Os artigos são parcialmente baseados na documentação da MSDN de onde são citadas as respectivas referências.

Iniciando com o Entity Framework

Conceito

A ADO .NET Entity Framework foi projetado para permitir que a criação de aplicações com acesso a dados use o modelo de programação feito contra um modelo conceitual ao invés do antigo modelo de programação feito diretamente contra um banco de dados relacional. O objetivo é diminuir a quantidade de código e o tempo de manutenção necessária exigida nestas aplicações orientada a dados.

A ADO .NET Entity Framework é uma framework que abstrai o esquema de um banco de dados relacional e o apresenta como um modelo conceitual. Abaixo a figura que representa a arquitetura em camadas do Entity Framework: (Até o lançamento do VS 2010, previsto para o primeiro trimestre.)

Data Source :  Representa a base da arquitetura onde estão armazenados os dados;

Data Providers :  Os dados são acessados por um ADO.NET data provider.  Até o momento tanto o SQL Server como o MySQL são suportados e provavelmente em breve os principais RDBMS do mercado (Oracle, MySQL, DB2, Firebird, Sybase, VistaDB, SQLite, ...) terão um provider para o EF.

Entity Data Model (EDM) :  O  Entity Data Model  é constituído de 3 partes:

  • Conceptual schema definition language (CSDL) : Declara e define entidades, associações, herança, etc,. As Entity classes são geradas a partir deste esquema;
  • Store schema definition language (SSDL) : Metadados que descreve o container de armazenamento (=banco de dados) que persiste os dados;
  • Mapping specification language (MSL) : Mapeia as entidades no arquivo CSDL para tabelas descritas no arquivo SSDL;

Entity Client : O EntityClient é um provedor gerenciado ADO.NET que suporta o acesso a dados descritos no EDM. Ele é similar ao SQLClient, e fornece diversos componentes como EntityCommand, EntityConnection e EntityTransaction;

Object Services : Este componente permite realizar consultas, atualizações, inclusões e exclusões nos dados, expressados como objetos CLR fortemente tipados que são instâncias de entity types. Ele da suporte tanto a consultas Entity SQL como LINQ to Entities;

Entity SQL (ESQL) : É uma derivação da Transact-SQL, projetada para consultar e manipular entidades definidas no EDM. Ele dá suporte herança e associação sendo que tanto os componentes Object Services como os componentes Entity Client podem executar instruções Entity SQL;

LINQ to Entities : É uma linguagem de consulta fortemente tipada para consultar entidades definidas no EDM;
 

Criar, modificar e deletar objetos e aplicar estas alterações ao banco de dados é muito fácil com o Entity Framework. Através do Object Services que gerencia todas as alterações feitas nos objetos e gera e executa as instruções T-SQL que irão realizar as operações de inclusão, alteração  e exclusão contra a fonte de dados. Tudo isso é feito através da chamada do método SaveChanges do ObjectContext (equivalente ao SubmitChanges do LINQ to SQL).

Vamos a seguir dar alguns exemplos usando o modelo conceitual (EDM) gerado no artigo anterior a partir do banco de dados Northwind.mdf.

1-  Atualizando uma entidade do modelo

Vamos mostrar como atualizar uma entidade do modelo. No caso a entidade Employees usando a linguagem C#:

      private void btnAlterar_Click(object sender, EventArgs e)
        {
            int resultado = 0;
            contexto = new NorthwindEntities();
            Employees empregado = contexto.Employees.First(emp => emp.EmployeeID == 1);
            if (empregado != null)
            {
                empregado.City = "Brasilia";
                empregado.Notes = "Nova nota par ao empregado";
                empregado.Country = "Brasil";
                resultado = contexto.SaveChanges();
            }
            lstDados.Items.Add("Objetos alterados : " + resultado);
            lstDados.Items.Add("City = " + empregado.City);
            lstDados.Items.Add("Country = " + empregado.Country);
            lstDados.Items.Add("Notes = " + empregado.Notes);
        }

Usando o método de extensão First() retornamos o empregado de código igual a 1. (Tentei usar o método Single mas ele não é suportado pela LINQ to Entities)

Em seguida fizemos algumas alterações e persistimos as alterações no banco de dados para em seguida exibir o resultado no controle ListBox.

2-   Criando uma entidade do modelo

Vejamos agora como criar um novo objeto. Como exemplo irei criar um objeto Categories:

        private void btnCriar_Click(object sender, EventArgs e)
        {
            contexto = new NorthwindEntities();
            Categories novaCategoria = new Categories();
            novaCategoria.CategoryName = "Teste";
            novaCategoria.Description = "Teste inclusão nova categoria";
            novaCategoria.Picture = null;
            contexto.AddToCategories(novaCategoria);
            try
            {
                contexto.SaveChanges();
                exibirObjetos();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Erro : " + ex.InnerException);
            }
        }

Criamos um novo objeto Categories e definimos os valores para as propriedades : CategoryName, Description e Picture.

Observe que não foi necessário atribuir um valor para a propriedade CategoryID que no banco de dados é uma chave primária auto incremental do tipo Identity.

Usamos o método AddToEmployees do ObjectContext (cada entidade possui um método do tipo gerado automaticamente com o nome AddToNomeEntidade) para incluir o novo objeto no ObjectContext e em seguida chamamos o método SaveChanges();

Poderíamos também usar o método AddObject() do ObjectContext para incluir o novo objeto no contexto. Para o exemplo a linha de código usada seria:

contexto.AddObject("Categories", novaCategoria);

Uma outra forma de criar um objeto é usar o método CreateCategories() existente no contexto de forma a instanciar uma nova Categoria e todas as propriedades requeridas (not Null);

Para o nosso exemplo usando a entidade Categories teríamos:

Categories novaCategoria = Categories.CreateCategories(0, "Nova Categoria");

Observe que a propriedade CategoryID é um campo requerido mas é preenchido pelo SQL Server pois é um campo auto-incremental no entanto tivemos que informar um valor qualquer , no caso o valor zero.  As propriedades Description e Picture são not Null e portanto recebem um valor null não sendo necessário informar seus valores.

3 -  Criando uma entidade com entidades associadas

Vamos agora criar um objeto Categories e um objeto Products associados. Podemos ver na figura que existe um relacionamento do tipo um-para-muitos entre as entidades Categories e Products e neste caso queremos incluir uma categoria e um produto relacionado.

O código abaixo cria um novo objeto Categories e define algumas propriedades e a seguir inclui um novo produto para a nova categoria.

       private void btnCriar2_Click(object sender, EventArgs e)
        {
            contexto = new NorthwindEntities();
            Categories novaCategoria = new Categories();
            novaCategoria.CategoryName = "Software";
            novaCategoria.Description = "Produtos - Software";
            novaCategoria.Products.Add(new Products { ProductName = "Microsoft Visual Studio 2010" });
            novaCategoria.Products.Add(new Products() { ProductName = "SilverLight 3" });
            contexto.AddToCategories(novaCategoria);
            contexto.SaveChanges();

            exibirObjetos();
            gdvProdutos.DataSource = novaCategoria.Products;
        }

 

Quando você cria uma nova entidade que esta associada com outra entidade pela propriedade de navegação( Navigation Properties) , você pode chamar o método Add() desta coleção, e, foi isso que fizemos para criar dois novos objetos Products e então adicioná-los a coleção de Categories;

  novaCategoria.Products.Add(new Products { ProductName = "Microsoft Visual Studio 2010" });
  novaCategoria.Products.Add(new Products() { ProductName = "SilverLight 3" });

Para incluir a categoria no contexto usamos o método AddToCategories() e em seguida chamamos o método SaveChanges para persistir as alterações na base de dados:

           contexto.AddToCategories(novaCategoria);
           contexto.SaveChanges();

Abaixo temos o resultado obtido para o exemplo: 

4 -  Excluindo uma entidade

Excluir um objeto do contexto é uma tarefa bem simples e para isso usamos o método DeleteObject().

Abaixo temos o código que pretende excluir um objeto Categories do contexto:

    private void btnExcluir_Click(object sender, EventArgs e)
        {
            contexto = new NorthwindEntities();
            Categories cat = contexto.Categories.First(c => c.CategoryName == "Software");
            contexto.DeleteObject(cat);
            try
            {
                contexto.SaveChanges();
                exibirObjetos();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Erro : " + ex.InnerException);
            }
        }

 

Primeiro obtemos um objeto Categories

 Categories cat = contexto.Categories.First(c => c.CategoryName == "Software");

A seguir chamamos o método DeleteObject() do contexto do objeto e passamos o objeto Categories e chamamos o método SaveChanges para persistir as mudanças.

Neste exemplo irá ocorrer uma exceção quando o método SaveChanges for executado :

"The DELETE statement conflicted with the REFERENCE constraint "FK_Products_Categories". The conflict occurred in database "Northwind", table "dbo.Products", column "CategoryID". The statement has been terminated."

Isto indica um conflito na tabela Products com a coluna CategoryID.

Para poder  realizar a exclusão  você terá que alterar a regra de exclusão (Delete Rule) definida para a chave estrangeira FK_Products_Categories  no banco de dados Northwind.mdf definindo-a como Cascade.

Após realizar esta alteração a exclusão será permitida.

 

Se o problema persistir você deverá modificar o arquivo XML .edmx manualmente verificando se a associação criada no arquivo CSDL (esquema conceitual) esta definida como Cascade:

<Association Name="FK_Products_Categories">  
  <End ...>  
    <OnDelete Action="Cascade" />
  </End>
</Association>

Dessa forma temos uma panorama geral de como realizar as principais operações com objetos em um mesmo contexto no Entity Framework.

Problemas relacionados com relacionamentos, concorrência, melhores práticas e desempenho serão tratados em outros artigos.

Pegue o projeto completo aqui: EF_crud2.zip

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

Referências:


José Carlos Macoratti