Posts Tagged ‘.Net’
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.
Trabalhando com arquivos .INI em .Net com Nini
quarta-feira, agosto 19th, 2009Os arquivos de configuração .INI há um bom tempo foram substituídos no .Net pelos arquivos XML, muito mais flexíveis e padronizados. Entretanto, quando trabalhamos com sistemas legados, seja para fazer integrações, migrações ou o que quer que seja, acabamos nos deparando com os saudosos arquivos .INI. Ao invés de criar rotinas caseiras para trabalhar com estes arquivos, que tal uma biblioteca em C# que cumpra esse papel com louvor? A biblioteca Nini faz isto e muito mais: além dos arquivos .INI, ela abstrai o acesso a arquivos de configuração XML, .Net Config, Registry e argumentos de linha de comando. O site do projeto não possui nada, apenas os links para poder baixar, mas a documentação vem junto com o arquivo baixado.
Segue um exemplo do próprio manual da Nini:
1 2 3 4 5 | ; MyApp.ini [Logging] File Name = MyApp.log MessageColumns = 5 MaxFileSize = 40000000000000 |
1 2 3 4 5 6 7 8 | // Usando C# using Nini.Config; IConfigSource source = new IniConfigSource("MyApp.ini"); string fileName = source.Configs["Logging"].Get("File Name"); int columns = source.Configs["Logging"].GetInt("MessageColumns"); long fileSize = source.Configs["Logging"].GetLong("MaxFileSize"); |
1 2 3 4 5 6 7 8 | 'E usando VB.Net Imports Nini.Config Dim source As New IniConfigSource("MyApp.ini") Dim fileName As String = source.Configs("Logging").Get("File Name") Dim columns As Integer = source.Configs("Logging").GetInt("MessageColumns") Dim fileSize As Long = source.Configs("Logging").GetLong("MaxFileSize") |
Álcool ou Gasolina? – Aplicativo para Windows Mobile 6 para tirar sua dúvida
sexta-feira, agosto 7th, 2009Neste post vou apresentar um aplicativo para Windows Mobile 6 que recebe como entrada o valor do litro do álcool, da gasolina e exibe uma mensagem dizendo qual dos dois é mais vantajoso abastecer, bastante útil quando o seu veículo é flex.
Requisitos:
- Windows Mobile 6 Professional SDK Refresh
- Visual Studio 2005 com C#
O código é bem simples, o valor do litro do álcool é dividido pelo valor do litro da gasolina, se o resultado for maior ou igual a 0,7 compensa abastecer com gasolina, caso contrário, abasteça com álcool.
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 | using System; using System.Text; using System.Windows.Forms; namespace AlcoolGasolina { public partial class frmPrincipal : Form { public frmPrincipal() { InitializeComponent(); } /// Método de validação da entrada. Considera inválidos strings vazias e /// valores menores ou iguais a zero. private bool isValid(string valor) { // Não deve ser uma string vazia ou nula if (String.IsNullOrEmpty(valor)) return false; try { // deve ser um valor numérico válido double num = Convert.ToDouble(valor); // não deve ser menor ou igual a zero if (num > 0) return true; else return false; } catch (Exception) { return false; } } /// Verifica se os valores digitados são válidos e, em caso positivo, /// faz o cálculo e apresenta a mensagem para o usuário informando /// qual é mais viável abastecer, álcool ou gasolina. Se os valores /// não forem válidos para o cálculo, será exibida uma mensagem de /// alerta, informando que os valores de entrada são inválidos. private void btnCalcular_Click(object sender, EventArgs e) { if (isValid(txtAlcool.Text.Trim()) && isValid(txtGasolina.Text.Trim())) { double alcool = Convert.ToDouble(txtAlcool.Text.Trim()); double gasolina = Convert.ToDouble(txtGasolina.Text.Trim()); double resultado = alcool / gasolina; if (resultado >= 0.7) lblResultado.Text = "Abasteça com Gasolina"; else lblResultado.Text = "Abasteça com Álcool"; } else { MessageBox.Show("Valores de entrada inválidos.", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); } txtAlcool.Text = string.Empty; txtGasolina.Text = string.Empty; } /// Fecha a aplicação. private void mnuSair_Click(object sender, EventArgs e) { Application.Exit(); } /// Menu "Sobre...", exibe uma mensagem com o nome da aplicação, /// nome do autor e endereço do blog do autor. private void mnuSobre_Click(object sender, EventArgs e) { StringBuilder mensagem = new StringBuilder("Álcool ou Gasolina\n\n"); mensagem.Append("Por Rogério Bragil\n\nBlog do Bragil - www.bragil.net"); MessageBox.Show(mensagem.ToString(), "Sobre", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } } } |