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:
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:
|
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