Posts Tagged ‘Repository’
DAO Genérico e o Entity Framework – Parte 3
segunda-feira, março 8th, 2010Finalmente, vamos agora para a implementação do nosso DAO Genérico usando o Entity Framework. Na Parte 2 nós criamos a interface IDAO e também o ContextManager, um helper para a criação do contexto. A implementação será chamada GenericDAO e definirá, através de generics, dois tipos, sendo que um será o tipo do objeto que será persistido e o outro será o tipo (classe) do contexto do Entity Framework. Vamos para o código!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | using System; using System.Collections.Generic; using System.Data; using System.Data.Metadata.Edm; using System.Data.Objects; using System.Data.Objects.DataClasses; using System.Linq; using System.Linq.Expressions; using Net.Bragil.Data.Context; namespace Net.Bragil.Data.DAO { /// Repositório genérico para o Entity Framework com as operações mais /// comuns de persistência, como inserção, atualização, /// exclusão e seleção. public class GenericDAO<E, C> : IDAO<E, C>, IDisposable where E : EntityObject where C : ObjectContext { /// Contexto do Entity Framework private C context; /// Contexto do Entity Framework public C Context { get { return context; } set { context = value; } } /// Retorna o nome do EntitySet do objeto persistente private string entitySetName; /// Retorna o nome do EntitySet do objeto persistente protected string EntitySetName { get { if (String.IsNullOrEmpty(entitySetName)) { entitySetName = GetEntitySetName(typeof(E).Name); } return entitySetName; } } /// Construtor padrão, sem argumentos. Obtém o contexto do /// Entity Framework usando o ContextManager. public GenericDAO() { // Obtém o contexto this.context = ContextManager.GetContext<C>(); } /// Insere um novo objeto persistente public void Insert(E entity) { context.AddObject(EntitySetName, entity); } /// Atualiza um objeto existente. public virtual void Update(E entity) { EntityKey key; object originalItem; if (entity.EntityKey == null) // Obtém o entity key do objeto que será atualizado key = Context.CreateEntityKey(EntitySetName, entity); else key = entity.EntityKey; try { // Obtém o objeto original if (Context.TryGetObjectByKey(key, out originalItem)) { if (originalItem is EntityObject && ((EntityObject)originalItem).EntityState != EntityState.Added) { // Autaliza o objeto context.ApplyPropertyChanges(key.EntitySetName, entity); } } } catch (Exception ex) { throw ex; } } /// Exclui um objeto persistente public void Delete(E entity) { context.DeleteObject(entity); } /// Retorna um objeto que satisfaça a cláusula passada como parâmetro. public E SelectOne(Expression<Func<E, bool>> where) { return context.CreateQuery<E>(EntitySetName).Where(where).FirstOrDefault(); } /// Salva as alterações no banco de dados. public void SaveChanges() { context.SaveChanges(); } /// Retorna todos os objetos persistentes. public List<E> SelectAll() { return context.CreateQuery<E>(EntitySetName).ToList(); } /// Retorna um IQueryable com todos os objetos public IQueryable<E> QueryAll() { return context.CreateQuery<E>(EntitySetName).AsQueryable<E>(); } /// Retorna todos os objetos usando paginação. public List<E> SelectAll(int maximumRows, int startRowIndex) { return context.CreateQuery<E>(EntitySetName).Skip<E>(startRowIndex).Take(maximumRows).ToList(); } /// Retorna um IQueryable com todos os objetos usando paginação public IQueryable<E> QueryAll(int maximumRows, int startRowIndex) { return context.CreateQuery<E>(EntitySetName).Skip<E>(startRowIndex).Take(maximumRows); } /// Retorna todos os objetos que satisfaçam a cláusula passada public List<E> SelectWhere(Expression<Func<E, bool>> where) { return context.CreateQuery<E>(EntitySetName).Where(where).ToList(); } /// Retorna todos os objetos que satisfaçam a cláusula passada, usando paginação public List<E> SelectWhere(Expression<Func<E, bool>> where, int maximumRows, int startRowIndex) { return context.CreateQuery<E>(EntitySetName).Where(where) .Skip<E>(startRowIndex).Take(maximumRows).ToList(); } /// Retorna o número de objetos public int GetCount() { return context.CreateQuery<E>(EntitySetName).Count(); } /// Retorna o número de objetos que satisfaçam a cláusula passada public int GetCount(Expression<Func<E, bool>> where) { return context.CreateQuery<E>(EntitySetName).Where(where).Count(); } /// Libera os recursos do Entity Framework. public void Dispose() { if (context != null) context.Dispose(); } /// Retorna o nome do EntitySet, possibilitando a criação de métodos genéricos. private string GetEntitySetName(string entityTypeName) { var container = context.MetadataWorkspace .GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace); string entitySetName = (from meta in container.BaseEntitySets where meta.ElementType.Name == entityTypeName select meta.Name).FirstOrDefault(); return entitySetName; } } } |
DAO Genérico e o Entity Framework – Parte 2
quinta-feira, março 4th, 2010Na primeira parte deste artigo, criamos o banco de dados e geramos o contexto do Entity Framework para o modelo. Agora, vamos começar a definir o componente para o DAO Genérico. Segue uma lista dos requisitos para o componente:
Deverá oferecer a possibilidade de trabalhar independente dos tipos envolvidos
Ou seja, poderemos usar o mesmo componente para persistir qualquer objeto, independente do contexto usado. Isso é facilmente conseguido através do uso de Generic Types, sendo possível parametrizar os tipos que serão trabalhados durante as operações de persistência.
Deverá simplificar o desenvolvimento para as rotinas básicas de persistência
O objetivo será tornar o desenvolvimento o mais simples possível, procurando encapsular todo o “trabalho sujo” e criar uma interface limpa e amigável para o programador.
Baseado nas especificações acima, segue a Interface do componente DAO para o Entity Framework:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace Net.Bragil.Data.DAO { /// Interface para a implementação do padrão Repository usando o Entity Framework. public interface IDAO<E, C> { /// Contexto do Entity Framework C Context { get; set; } /// Inserção void Insert(E entity); /// Atualização void Update(E entity); /// Exclusão void Delete(E entity); /// Retorna o objeto que satisfaça a cláusula passada como argumento (cláusula WHERE) E SelectOne(Expression<Func<E, bool>> where); /// Retorna todos os objetos de um tipo List<E> SelectAll(); /// Retorna os objetos usando paginação List<E> SelectAll(int maximumRows, int startRowIndex); /// Retorna todos os objetos que satisfaçam a cláusula passada List<E> SelectWhere(Expression<Func<E, bool>> where); /// Retorna os objetos que satisfaçam a cláusula passada, usando paginação List<E> SelectWhere(Expression<Func<E, bool>> where, int maximumRows, int startRowIndex); /// Retorna um objeto IQueryable, possibilitando formar queries usando expressões Lambda IQueryable<E> QueryAll(); /// Retorna um IQueryable com os objetos usando paginação IQueryable<E> QueryAll(int maximumRows, int startRowIndex); /// Retorna a quantidade de objetos persistentes. int GetCount(); /// Retorna a quantidade de objetos persistentes que satisfaçam a cláusula WHERE int GetCount(Expression<Func<E, bool>> where); } } |
Como você pode ver, o componente oferecerá a maioria dos recursos de persistência, de uma forma muito mais amigável do que usando o Entity Framework diretamente.
Foi necessário também a criação de uma classe auxiliar para instanciação do contexto do Entity Framework usando a estratégia “One-Per-Request”, ou seja, é criada apenas uma instância do contexto por requisição. O objeto do contexto é armazenado em HttpContext.Current.Items, de modo que as chamadas subsequentes dentro da mesma requisição retornam o contexto anteriormente instanciado e armazenado na requisição. Segue o código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | using System.Web; using System.Data.Objects; namespace Net.Bragil.Data.Context { /// Classe gerenciadora do contexto do Entity Framework. Utiliza generics /// para determinar em tempo de execução o tipo do contexto e Reflection /// para instanciar o tipo genérico. Armazena o contexto no HttpContext, /// de modo que não seja necessário instanciar o contexto nas próximas /// chamadas dentro da requisição web. public sealed class ContextManager { /// Construtor privado, não será possível instanciar a classe usando new private ContextManager() { } /// Obtém o contexto do Entity Framework usando generics. public static T GetContext<T>() where T: ObjectContext { string ocKey = "ocm_" + HttpContext.Current.GetHashCode().ToString("x"); if (HttpContext.Current != null) { if (!HttpContext.Current.Items.Contains(ocKey)) { // Instancia o contexto através de Reflection T ctx = typeof(T).GetConstructor(System.Type.EmptyTypes) .Invoke(System.Type.EmptyTypes) as T; // Armazena na requisição HttpContext.Current.Items.Add(ocKey, ctx); } return HttpContext.Current.Items[ocKey] as T; } else // Caso a aplicação não seja web, instancia e retorna o contexto. return typeof(T).GetConstructor(System.Type.EmptyTypes) .Invoke(System.Type.EmptyTypes) as T; } } } |
Já estamos quase lá! No próximo artigo vamos desenvolver a implementação da classe GenericDAO.
DAO Genérico e o Entity Framework – Parte 1
quinta-feira, março 4th, 2010Este é o primeiro de uma série de 3 artigos abordando a criação de um DAO Genérico para o Entity Framework. Para quem não sabe, o DAO (Data Access Object) é um Design Pattern que abstrai as complexidades da camada de acesso a dados, oferendo uma interface de mais alto nível que possibilita um menor acoplamento com a tecnologia de persistência. Para um melhor entendimento, vamos apresentar de forma prática a criação da camada de persistência para um modelo simples de banco de dados, a geração do contexto do Entity Framework, o desenvolvimento do DAO e finalmente um pequeno exemplo mostrando os recursos do componente criado.
Os requisitos para o desenvolvimento proposto são os seguintes:
- Visual Studio 2008 SP1
- .Net Framework 3.5
- Banco de dados SQL Server Express Edition
Obs: é importante salientar que há outros bancos de dados cujos drivers possuem suporte ao Entity Framework. Verifique se o banco de dados que você usa possui driver para .Net com suporte ao Entity Framework.
Vamos trabalhar com um modelo de dados bem simples, mas suficiente para o nosso exemplo, conforme segue:

Basicamente, um cadastro simples de pessoas com endereço completo. Depois de definido o modelo de dados, vamos realizar a geração do contexto do Entity Framework (edmx). Se você não sabe como fazer isso, leia este artigo.
Pronto, já temos o banco de dados e o contexto do Entity Framework. O tipo do objeto de contexto do Entity Framework foi nomeado como DbEntities.

No próximo artigo vamos abordar o desenvolvimento do componente DAO.