Paulo Roberto 的个人资料Somos a última geração照片日志列表更多 ![]() | 帮助 |
|
|
10月22日 Auditoria de dados, usando NHibernateO NHibernate possui alguns eventos padrão que nos permitem fazer alguma coisa quando um objetos é incluído, excluido ou carregado do banco de dados. São os chamados EventListeners, realmente não tem muita documentação sobre o assunto, então, fazer qualquer coisa sobre isso, demanda uma boa pesquisa. Comecei aqui a implementar algo, então, vou poupar vocês de algum trabalho. No meu caso, eu preciso registrar as mudanças de informações que uma determinada classe sofreu, e quem realizou a mudança. Isso deve ficar armazenado no banco de dados. Logo, defini a seguinte classe: 1: public class Historico 2: {3: private Int64 _id; 4: private string _classe; 5: private string _alteracoes; 6: 7: public virtual Int64 Id 8: {9: get { return _id; } 10: set{ _id = value;} 11: } 12: 13: public virtual string Classe 14: {15: get{ return _classe;} 16: set{ _classe = value;} 17: 18: } 19: 20: public virtual string Alteracoes 21: {22: get { return _alteracoes; } 23: set{ _alteracoes = value;} 24: } 25: 26: public Historico() 27: { 28: Id = 0;29: Classe = string.Empty; 30: Alteracoes = string.Empty; 31: } 32: 33: public Int64 IdObjeto { get; set; } 34: public string Acao { get; set; } 35: public DateTime Data { get; set; } 36: public string Usuario { get; set; } 37: }
Nada complicado. Definimos aí uma propriedade Classe que irá armazenar o nome da classe que sofre alteração, uma propriedade Historico, que irá conter as alterações feitas, IdObjeto que guarda o Id do objeto que sofre alteração; Acao, que guarda o tipo de acontecido, Data que representa quando foi alterado e Usuario, que guarda o nome do usuario que fez a alteração. Como essa classe deve ser persistida, é preciso também fazer seu mapeamento. Não vou entrar em detalhes como fazer isso… Agora chegou a hora de implementarmos os eventos. Para registrar o que foi alterado, é preciso implementar a interface IPostUpdateEventListener. Ela disponibiliza o método OnPostUpdate. Esse evento é disparado depois que o objeto foi atualizado. A seguir temos a classe de auditoria. 1: public class LogAlteracao : IPostUpdateEventListener 2: {3: private const string _noValueString = " "; 4: 5: private static string getStringValueFromStateArray(object[] stateArray, int position) 6: {7: var value = stateArray[position]; 8: 9: return value == null || value.ToString() == string.Empty 10: ? _noValueString11: : value.ToString(); 12: } 13: 14: public void OnPostUpdate(PostUpdateEvent @event) 15: {16: if (@event.Entity is Historico) 17: {18: return; 19: } 20: 21: var entityFullName = @event.Entity.GetType().FullName; 22: 23: if (@event.OldState == null) 24: {25: var session = @event.Session.GetSession(EntityMode.Poco); 26: var sb = new StringBuilder(); 27: 28: for (int i = 0; i <= @event.State.Count() - 1; i++) 29: {30: var newValue = getStringValueFromStateArray(@event.State, i); 31: sb.AppendLine("Propriedadade: " + @event.Persister.PropertyNames[i]); 32: sb.AppendLine(" Novo valor..: " + newValue); 33: sb.AppendLine("-------------------------------"); 34: } 35: 36: var historico = new Historico(); 37: historico.Classe = @event.Entity.GetType().Name; 38: historico.IdObjeto = (Int64)@event.Id; 39: historico.Acao = "Atualização"; 40: historico.Alteracoes = sb.ToString(); 41: historico.Data = DateTime.Now; 42: session.Save(historico); 43: }44: else 45: {46: var dirtyFieldIndexes = @event.Persister.FindDirty(@event.State, @event.OldState, @event.Entity, 47: @event.Session); 48: 49: var session = @event.Session.GetSession(EntityMode.Poco); 50: var sb = new StringBuilder(); 51: 52: foreach (var dirtyFieldIndex in dirtyFieldIndexes) 53: { 54: 55: //Aqui tem que testar se for component. 56: //Se for, tem que pegar as propriedades manualmente... por reflection 57: if (@event.Persister.PropertyTypes[dirtyFieldIndex] is ComponentType) 58: {59: // Recupera o estado atual e o anterior da propriedade. 60: var obj = @event.State[dirtyFieldIndex]; 61: var objAnterior = @event.OldState[dirtyFieldIndex]; 62: 63: var propertyInfos = obj.GetType().GetProperties();64: foreach (var info in propertyInfos) 65: {66: // Se a propriedade não pode ser lida, não faz nada. 67: if (!info.CanRead) 68: continue; 69: 70: try 71: {72: // Recupera os valor novo e o antigo da propriedade. 73: var novoValor = info.GetValue(obj, null); 74: var valorAntigo = info.GetValue(objAnterior, null); 75: 76: // Verifica se são mesmo diferentes. 77: if (valorAntigo.ToString().Equals(novoValor.ToString())) 78: continue; 79: 80: sb.AppendLine("Propriedadade: " + info.Name); 81: sb.AppendLine(" Valor antigo: " + valorAntigo); 82: sb.AppendLine(" Novo valor: " + novoValor); 83: sb.AppendLine("-------------------------------"); 84: }85: catch 86: {87: continue; 88: } 89: } 90: }91: else 92: {93: var oldValue = getStringValueFromStateArray(@event.OldState, dirtyFieldIndex); 94: var newValue = getStringValueFromStateArray(@event.State, dirtyFieldIndex); 95: 96: if (oldValue == newValue) 97: {98: continue; 99: } 100: 101: sb.AppendLine("Propriedadade: " + @event.Persister.PropertyNames[dirtyFieldIndex]); 102: sb.AppendLine(" Valor antigo: " + oldValue); 103: sb.AppendLine(" Novo valor..: " + newValue); 104: sb.AppendLine("-------------------------------"); 105: } 106: } 107: 108: var historico = new Historico(); 109: historico.Classe = @event.Entity.GetType().Name; 110: historico.IdObjeto = (Int64) @event.Id; 111: historico.Acao = "Atualização"; 112: historico.Alteracoes = sb.ToString(); 113: historico.Data = DateTime.Now; 114: session.Save(historico); 115: session.Flush(); 116: } 117: } 118: }
Vamos dar uma entendida no código…. Todas informações que vamos precisar estão acessíveis no parêmetro PostUpdateEvent event. A primeira coisa que verificamos é se, o objeto que está vindo é Historico. Se for, não fazemos nada… senão ia ficar em loop, certo? Na sequência verificamos se o objeto possui um OldState. Essa propriedade representa o estado do objeto antes da alteração e só é preenchida se o objeto tiver sido carregado pelo Session que está em uso. Caso o objeto não tenha OldState, percorremos a propriedade State, que contém os valores atuais, e montamos com esses valores uma string para ser salva. Então instanciamos um objeto Historico e salvamos o objeto. Agora, se o objeto tem um OldState, podemos gerar histórico só do que foi alterado. Veja a linha 46. O NHibernate disponibiliza o método FindDirty, que retorna os índices das propriedades que sofreram alterações. Aí é só montar novamente o texto e salvar… Quero apontar um detalhe lá na linha 57. Estamos verificando se a propriedade que vem é do tipo ComponentType. Quando no mapeamento de uma classe, mapeamos outra nela como Component, ela aparece nesse evento PostUpdate como uma única propriedade. Assim, é necessário usarmos reflection pra extrair as propriedades….. Talvez precise melhorar algo aí nessa implementação, mas por enquanto… está funcionando :). Depois posto como registrar as exclusões.
10月5日 Configurando o NHibernate por códigoOlá pessoal. Aqui temos a necessidade de flexibilizar a string de conexão do sistema, de tal forma que o usuário possa mudá-la a partir de uma tela de configurações. Outro detalhe que prevemos, é a mudança de banco de dados sem a necessidade de recompilar o projeto. Levando tudo isso em consideração, mais a possibilidade de adicionar algum parâmetro de execução e habilitar ou não a exibição de SQL ou geração de estatísticas, resolver configurar o NHibernate por código. Contudo o desafio em fazer isso estava no fato de que utilizamos o projeto uNHaddins. Até o momento estávamos utilizando a classe DefaultSessionFactoryConfigurationProvider(), responsável por carregar e configurar o NHibernate. A solução foi criar uma classe herdada de AbstractConfigurationProvider. Essa classe abstrata expoem os métodos necessários que devem ser implementados para que possam ter uma inicialização personalizada do NHibernate. Sendo assim temos a seguinte classe: /// <summary> /// Esta classe configura manualmente, por código, as propriedades do NHibernate. /// Estamos fazendo por código para facilitar a troca de connection string e até mesmo /// a troca de banco de dados. /// </summary> public class ByCodeConfigurationProvider: AbstractConfigurationProvider { private readonly string _connectionString; private Configuration _configuration; /// <summary> /// Construtor da classe. Recebe como parâmetro <paramref name="connectionString"/> /// </summary> /// <param name="connectionString">String de conexão do banco de dados em uso</param> public ByCodeConfigurationProvider(string connectionString) { _connectionString = connectionString; } private void ConfigureByCode() { if (_configuration == null) { _configuration = new Configuration(); _configuration.SetProperty("connection.driver_class","NHibernate.Driver.SqlClientDriver"); _configuration.SetProperty("hbm2ddl.auto","update"); _configuration.SetProperty("show_sql","true"); _configuration.SetProperty("connection.connection_string",@"Data Source=SRV2003NET\SQLEXPRESS;Initial Catalog=NotasBD;Persist Security Info=True;User ID=NotasMaster;Password=cont10rol"); _configuration.SetProperty("adonet.batch_size","10"); _configuration.SetProperty("dialect","NHibernate.Dialect.MsSql2005Dialect"); _configuration.SetProperty("use_outer_join","true"); _configuration.SetProperty("command_timeout","10"); _configuration.SetProperty("query.substitutions","true 1, false 0, yes 'Y', no 'N'"); _configuration.SetProperty("current_session_context_class","uNhAddIns.SessionEasier.Conversations.ThreadLocalConversationalSessionContext, uNhAddIns"); _configuration.SetProperty("proxyfactory.factory_class","NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle"); _configuration.SetProperty("use_proxy_validator","false"); _configuration.AddAssembly(Assembly.GetAssembly(typeof (Pessoa))); var eventos = _configuration.EventListeners; eventos.PreUpdateEventListeners = new List<IPreUpdateEventListener>(eventos.PreUpdateEventListeners){new EventListener()}.ToArray(); eventos.PreInsertEventListeners = new List<IPreInsertEventListener>(eventos.PreInsertEventListeners){new EventListener()}.ToArray(); } } public override IEnumerable<Configuration> Configure() { ConfigureByCode(); return new SingletonEnumerable<NHibernate.Cfg.Configuration>(_configuration); } } Como pode ser visto, o método ConfigureByCode instancia um objeto Configuration do NHibernate e utilizando o método SetProperty, configura suas propriedades. O construtor da classe recebe como parâmetro uma string que contém a connection string do banco, porém não estamos utilizando nesse momento. Mas o detalhe da flexibilização é que como estamos fazendo tudo por código, é muito fácil ler algum arquivo de configuração e mudar essas propriedades como desejarmos, sem termos que recompilar código. Aqui centralizamos a carga de nossos serviços em uma classe tipo ServiceLocator, e nela executamos a carga do NHibernate assim:
public class ServiceLocatorProvider { public static void Initialize() { var container = new WindsorContainer(); container.AddFacility<PersistenceConversationFacility>(); var nhConfigurator = new ByCodeConfigurationProvider(""); var sfp = new SessionFactoryProvider(nhConfigurator); container.Register(Component.For<ISessionFactoryProvider>().Instance(sfp)); container.Register(Component.For<ISessionWrapper>().ImplementedBy<SessionWrapper>()); container.Register(Component.For<IConversationFactory>().ImplementedBy<DefaultConversationFactory>()); container.Register(Component.For<IConversationsContainerAccessor>().ImplementedBy<NhConversationsContainerAccessor>()); container.Register(Component.For<ISessionFactory>().Instance(sfp.GetFactory(null))); container.Register(Component.For(typeof(IDao<>)).ImplementedBy(typeof(BaseDao<>)).LifeStyle.Transient); var sl = new WindsorServiceLocator(container); container.Register(Component.For<IServiceLocator>().Instance(sl)); ServiceLocator.SetLocatorProvider(() => sl); }}
Segue aí a dica! 3月26日 Relacionamentos MxN com NHibernateTodos sabemos que manter um relacionamento MxN é chato. E claro que ao utilizar uma ferramenta ORM podemos minimizar essa dor de cabeça. Imaginem que em seu banco de dados exista a seguinte situação:
Nosso modelo de objetos está da seguinte forma: Observe que em nenhum momento temos alguma classe que representa a tabela associativa TURMA_X_ALUNO. É no mapeamento das classes que vamos indicar a existência dessa tabela e informar ao NHibernate que a coleção Turmas e Alunos devem utilizá-la. Vamos ver primeiramento o mapeamento da classe Aluno. <?xml version="1.0" encoding="utf-8" ?> Destaquei em azul a parte que nos interessa. Veja que utilizamos uma idbag para representar a coleção de Turmas. Ela foi utilizada porque nossa tabela associativa possui uma chave primária própria, que está mapeada na tag colection-id. Em vermelho estão destacadas coisas importantes também. Definimos que a tabela que mantém a coleção de Turmas é nossa tabela associativa e informamos ao NHibernate que não é por aqui que vamos realizar as associações. Isso quer dizer que não vamos adicionar turmas aos alunos mas sim, alunos às turmas existentes. Então se eu fizer algo assim: Aluno.Turmas.Add(novaTurma); Essa nova associação não será salva, porque a marcamos com inverse=true. Depois dizemos que essa mesma associação é many-to-many, informando também de qual classe. Dessa forma, automaticamente o NHibernate já sabe como preencher a lista Turmas. Quanto ao mapeamento de Turma, é semelhante, veja. <?xml version="1.0" encoding="utf-8" ?> <idbag name="Alunos" table="TURMA_X_ALUNO" generic="true" lazy="true" cascade="save-update"> <key column="ID_TURMA" /> A diferença é que não especificamos aqui a tag inverse=true é porque é por aqui que vamos realizar as associações. Veja um teste feito: Configuration cfg = new Configuration(); Aluno objAluno1 = new Aluno(); Aluno objAluno2 = new Aluno(); session.Save(objAluno1); Turma objTurma = new Turma(); objTurma.Alunos.Add(objAluno1); session.Save(objTurma); É muito simples manter esse tipo de relacionamento com o NHibernate, o detalhe como sempre, é acertar no mapeamento. Observe também que não estou usando mais ids do tipo identity, após recomendação do meu último post… Abraço a todos…
3月20日 Evite o uso do recurso Identity do SQLServer quando utilizar NHibernateHoje Tuna Toksoz fez um post interessante no site do NHibernate. Ele explica porque evitar o uso do Identity. Vou resumir o post aqui. Basicamente quando se usa o Identiy, o recurso de batching do NHibernate fica impossibilitado de ser aplicado. Ele mostra isso utilizando os seguintes códigos: 1: [Test]2: public void Should_not_insert_entity_in_a_transaction_HiLo() 3: {4: var post = new PostWithHiLo {Title = "Identity Generators Revealed"}; 5: var postComment = new PostCommentWithHiLo { Post = post, Comment = "Comment" }; 6: using (ISession session = factory.OpenSession()) 7: using (var tran = session.BeginTransaction()) 8: {9: session.Save(post); //No commit here 10: session.Save(postComment);11: long insertCount = factory.Statistics.EntityInsertCount; 12: Assert.That(insertCount, Is.EqualTo(0), "Shouldn't insert entity in a transaction before commit."); 13: } 14: } 15: 16: [Test]17: public void Should_not_insert_entity_in_a_transaction_Identity() 18: {19: var post = new PostWithIdentity {Title = "Identity Generators Revealed"}; 20: var postComment = new PostCommentWithIdentity {Post = post, Comment = "Comment"}; 21: using (ISession session = factory.OpenSession()) 22: using (var tran = session.BeginTransaction()) 23: { 24: session.Save(post); 25: session.Save(postComment);26: long insertCount = factory.Statistics.EntityInsertCount; 27: Assert.That(insertCount, Is.EqualTo(0), "Shouldn't insert entity in a transaction before commit."); 28: } 29: }No primeiro teste, que não utiliza Identity, nada é enviado para o banco. Já no segundo teremos 2 comandos INSERT enviados ao banco. Isso significa que podemos enfrentar problemas de performance, já que o banco será acessado várias vezes. Pra finalizar ele mostra um último exemplo: 1: using (ISession session = factory.OpenSession()) 2: using (var tran = session.BeginTransaction()) 3: {4: for (int i = 0; i < 3; i++) 5: {6: var post = new PostWithHiLo {Title = string.Format("Identity Generators Revealed {0}", i)}; 7: session.Save(post); 8: } 9: tran.Commit(); 10: }Neste caso os três comandos INSERT que são gerados, só são enviados após o commit e de uma vez só ao banco. Se estivéssemos utilizando Identity, a cada Save teríamos um INSERT sendo enviado. Para ver o post completo, acesse o link: http://nhforge.org/blogs/nhibernate/archive/2009/03/20/nhibernate-poid-generators-revealed.aspx Até mais! 11月11日 Palestra sobre NHibernateNesta semana está acontecendo na UNAERP, em Ribeirão Preto/SP, a 12ª semana da tecnologia. Ontem pude realizar uma palestra sobre NHibernate. Quero agradecer a todos que compareceram e à comissão organizadora. Infelizmente o tempo não foi suficiente pra mostrar tudo o que gostaria, de qualquer forma, estou aqui para retirar qualquer dúvida. obrigado! 10月21日 WPF + Model-View-ViewModel + NHibernateEstou liberando aqui um pequeno exemplo que mostra como utilizar o NHibernate em um aplicação WPF, empregando o padrão M-V-VM. Além disso utilizo também uma implementação do padrão Repository e Unit of Work, ambos descritos pelo NHibernate FAQ. Este demo utiliza a versão Embedded do Firebird 2.1 e para rodar é necessário apenas um pequeno ajuste no arquivo aliases.conf, localizado na pasta debug da aplicação. O ajuste a ser feito é apenas informar o path correto da localização do banco de dados. Qualquer dúvida é só deixar um recado aqui. PS.: Estou com o tempo curto, por isso não fiz um post explicando como tudo foi feito…. 3月31日 NHibernate 2.0 ALPHA 1É isso mesmo, depois de um tempo sem novidades saiu a nova versão. Mesmo sendo ALPHA existem várias pessoas utilizando, segundo o Ayende. Vou listar aqui algumas novidades...
E vários itens do Hibernate foram portados, entre eles:
E alguns subprojetos importantes foram adicionados
Faça o download agora mesmo em: http://sourceforge.net/project/showfiles.php?group_id=73818 Lembrando... houve mudanças significativas, que podem quebrar seu código... saiba mais no blog do Ayende PS.: Olha que legal o logo que o ayende fez
2月7日 Exemplos de mapeamento com NHibernateQuem inicia com NHibernate com frequência se defronta com a pergunta: "como que posso mapear este relacionamento ?". Para nos ajudar o Davy Brion, em seu blog, postou uma série de exemplos... para acessar o blog dele, cliquem aqui 12月13日 NHibernate deixando sua aplicação "lenta" ???No último dia 10 o Ben Scheirman conta uma situação que ele enfrentou referente o desempenho de uma aplicação sua, que não estava satisfatório, e que usava o nhibernate. Ele relata aqui em detalhes e relaciona alguns pontos importantes... que tomei a liberdade fazer uma tradução livre deles.
Não deixem de ler na íntegra o post dele... 12月12日 NHibernate e WPFQuem começou a estudar o WPF percebeu que existe agora os tipos "observable collection". Quem usa o NHibernate e quer mapear uma lista Observable, sabe que não vai dar certo... Aqui vai a dica então, encontrei neste blog uma implementação de IUserCollectionType, disponível a partir da versão 1.2.0, que oferece suporte ao WPF para sets, list e bag. Em seu blog, Adrian Alexander disponibiliza os fontes e um projeto de exemplo. Baixem lá e não deixem de agredecê-lo pelo ótimo trabalho.
PS.: Adrian, really thanks ! 11月30日 NHibernate 1.2.1No último dia 26 saiu uma atualização do NHibernate.... não percam Build 1.2.1
========================
Bug Fixed:
* [NH-111] - Oracle "Invalid identifier" exception
* [NH-989] - Assemblies are not registered in the correct order
* [NH-995] - Problem with CompositeId+"key-many-to-one"+Caching
* [NH-999] - One Shot Delete doesn't work - and cause reference violations
* [NH-1006] - Invalid SQL order generated by JetDriver
* [NH-1011] - update=false attribute ignored
* [NH-1012] - DetachedCriteria CreateAlias with joinType (new in1.2) is broken
* [NH-1018] - 'DistinctRootEntity' result transformer throws InvalidCastException
* [NH-1023] - using projections and transformer causes invalid column name when property and alias are the same
* [NH-1039] - NullReferenceException for dynamic-component containing a set
* [NH-1061] - Schema name missing when quering for highest key value
* [NH-1064] - wrong association owner when fetching eagerly
* [NH-1068] - Typo in example-mappings.html
* [NH-1086] - SerializationException when using MemCacheProvider as cache because some classes miss the SerializableAttribute.
* [NH-1124] - Problem in NHibernate.Type.ComponentType.NullSafeSet
* [NH-1155] - SubselectFetch doesn't take into account paging
* [NH-1156] - MS2005Dialect doesn't handle same column & alias names correctly
* [NH-1167] - SubCriteria.CreateCriteria(string associationPath, string alias, JoinType joinType) always uses JoinType.InnerJoin
Improvements:
* [NH-901] - ComponentType mappings for with value types (structs) cause incorrect dirty checking
* [NH-1049] - classes which inherit Order can't override ToSqlString
New Features:
* [NH-1022] - Add command batching support for OracleClient driver
Patches Applied:
* [NH-585] - Unknown version when using replicate and joined-subclass
* [NH-903] - IQuery.SetFirstResult and SetMaxResults break in MsSql2005Dialect for ISQLQuery using WITH keyword
* [NH-990] - Abstract CurrentSessionContext management and add more implementations
* [NH-1014] - NHibernate Cross Join Syntax Causes Issues With SQL Server 2000/2005
* [NH-1054] - Add hibernate.transaction.factory_class setting
* [NH-1056] - Command batching support for OracleDataClientDriver
* [NH-1076] - Sybase11 Dialect
* [NH-1080] - HQL parser incorrectly registers a many-to-one association as a one-to-one.
* [NH-1119] - valuetypes in uniqueresult<T> give an error when query result is null
* [NH-1160] - Parameter compatibility problem in cached Sql command.
* [NH-1193] - Limit string in MsSql2005 dialect can sort incorrectly on machines with multiple processors
Task Completed:
* [NH-1002] - Document undocumented configuration properties5月28日 Sistema MinhaClínica
Durante esta semana cheguei a uma conclusão a respeito do projeto que será desenvolvido. Será um controle de fichas de pacientes médicos. Durante o desenvolvimento vamos explorar os requisitos. Originalmente esse pequeno sistema foi desenvolvido por mim em Delphi possuindo como base de dados um banco Firebird 2.0. A idéia por traz deste projeto é mostrar como o desenvolvimento OO pode facilitar nossas vidas de desenvolvedores. E para iniciar quero expor minhas razões do porque utilizar uma ferramenta ORM, em especial o NHibernate. Porque usar uma ferramenta ORM: Há vários anos os bancos de dados relacionas são utilizados como armazenamento de dados e sua eficiência para isso não se discute. Com o passar do tempo vários recursos foram adicionados aos SGBDs, como recursos de relatórios e até mesmo de geração de interface. Nesse mesmo tempo as tecnologias para desenvolvimento de sistemas, a programação propriamente dita, também evoluíram em resposta aos novos desafios que lhe eram impostos. Por exemplo os prazos foram diminuindo, novas plataformas como WEB e dispositivos móveis se popularizaram, a variedade de banco de dados relacionais existentes sem contar com a necessidade de se melhor representar o mundo real. Por esses e outros motivos a programação OO tem se firmado e crescido em uso. Ao utilizar OO como programação possuindo um banco relacional como fonte de dados será percebido o que formalmente é conhecido como “impendância objeto/relacional”. Isso se dá ao fato de que os objetos de negócio podem ser representados de forma diferente em um banco relacional. Por isso que surgiram as ferramentas ORM. ORM significa Object Relational Mapping, mapeamento objeto relacional. Uma ferramenta ORM tem por objetivo diminuir as diferenças entre objetos e tabelas de um SGBD. Devem oferecer formas para o desenvolvedor definir como que seus objetos serão persistidos (salvos) de forma física, e até mesmo como podem ser obtidos e manipulados do SGBD. Se você ainda não compreendeu imagine uma classe Pessoa que possui os seguintes atributos: Nome, RG, Endereço, sendo que Endereço é uma outra classe que possui os atributos Logradouro, Número, Complemente, Bairro, Cidade, Estado e CEP. Como vamos salvar esse objeto? Em que banco de dados? Para qual tabela? Em quais campos? É isso que uma ferramenta ORM oferece e utilizando uma poderíamos responder as questões acima da seguinte forma, a classe Pessoa é mapeada para uma Tabela Pessoa, e a classe Endereço poderia ter seus atributos mapeados para a mesma tabela Pessoa. Além de permitir isso, uma ferramenta ORM deve abstrair o banco de dados, seu acesso, sua manipulação através de SQL e até mesmo sua troca para permitir que o desenvolvedor mantenha o foco no que creio ser realmente importante, as regras de negócios que serão aplicadas ao sistema em desenvolvimento. Porque utilizar o NHibernate ? Além de oferecer os recursos comuns a qualquer ferramenta ORM que se preze temos:
5月21日 NHibernate + Windows formsHá algum tempo ando meio "revoltado" com os exemplos de uso do NHibernate que encontro na net. Posso dizer que praticamente todos são para ASP.NET. No mercado onde a empresa que trabalho atua é impossível aplicar um sistema web, isto devido à exeriência de uso do usuário. Então quero propor aqui um início de um projeto que mostrará como utilizar o NHibernate com windows forms. Além do NHibernate quero trocar experiências aqui sobre NUnit, NMvp, NCover e quem sabe chegar até mesmo nos builds automáticos. Quero contar com a ajuda de quem tem lido este blog, atraavés de sugestões e dicas, porque tbém não sei tudo, quero aprender com quem sabe mais do que eu :)
Fica aqui então.... vou definir durante a semana qual será o projeto...
PS.: O projeto não andará a passos largos, visto que faço isso no meu tempo livre...
5月14日 LINQ para NHibernate
A coqueluche do momento é o LINQ... utilizar sentenças da forma que o LINQ utiliza pode ser útil em alguns momentos e pensando nisso alguns colaboradores do projeto NHibernate já possuem uma implementação do LINQ para o NHibernate. Abaixo alguns links: Implementando LINQ para NHibernate - por Oren Eini Até mais |
|
|