VB .NET - Usando o NHibernate no VB 2008


Este artigo procura apresentar de forma clara e objetiva a utilização do NHibernate com o Visual Basic  2008 em uma aplicação muito simples de forma que o contato inicial com o NHibernate seja o menos traumático possível.

Mas afinal o que vem a ser esse tal de NHibernate ?

O NHibernate é um porte do consagrado framework HIbernate para Java para a plataforma .NET, dessa forma o NHibernate surgiu a partir do Hibernate um framework muito usado na plataforma Java.

O NHibernate é um framework para realizar o mapeamento objeto/relacional de modo a transformar os dados da estrutura lógica de um banco de dados relacional em objetos definidos no domínio de uma aplicação. Ele também realiza a persistência de objetos em banco de dados relacionais.

Para você entender o porquê da existência do NHibernate vamos a um pouco de história...

Os bancos de dados relacionais surgiram na década de 70 e substituíram os sistemas de arquivos. Com ele surgiu a linguagem SQL , uma poderosa linguagem para trabalhar com banco de dados relacionais. Com o passar do tempo o modelo foi sendo adotado e se consolidou entre as empresas, sendo utilizados em praticamente 99% das aplicações.

Passados mais de 30 anos podemos disser que as informações das grandes empresas estão sendo armazenados em bancos de dados relacionais e que a linguagem SQL é amplamente usada para recuperar e persistir informações.

As linguagens orientadas a objeto começaram a despontar na década de 80 e apenas há alguns anos se firmaram como uma tecnologia confiável que apresenta diversas vantagens sobre o antigo modelo procedural de desenvolvimento de software.

Temos então o seguinte cenário:

- Os banco de dados relacionais imperam por toda a parte;
- As empresas não querem mudar pois os bancos de dados relacionais são confiáveis e uma mudança para outro modelo seria cara e arriscada;
- O avanço da tecnologia,  a internet,  o grau de complexidade requerido nas aplicações atuais exigem um desenvolvimento onde o paradigma da orientação a objeto é o mais indicado;
- As novas aplicações usam cada vez mais o paradigma da orientação a objeto mas precisam armazenar informações em banco de dados relacionais;
- Existe uma lacuna entre o paradigma da orientação a objetos e os banco de dados relacionais;

Diante deste quadro quem poderá me nos ajudar ??? 

Ora , o NHibernate !!!! (na verdade existem outras ferramentas OR/M mas o foco deste artigo é o NHibernate)

  Usando o paradigma da programação orientada a objetos com um banco relacional como fonte de dados será percebido o que é conhecido como “impendância objeto/relacional”. Isso ocorre porque os objetos de negócio podem ser representados de forma diferente em um banco relacional. Por este motivo as ferramentas ORM surgiram. ORM significa Object Relational Mapping, mapeamento objeto relacional.

O NHIbernate tem o poder de transformar objetos em dados e dados em objetos.

A proposta do NHibernate é justamente ser a ponte entre os banco de dados relacionais com tabelas, registros , campos e o mundo dos objetos com  instâncias, classes, métodos e objetos, de forma que o desenvolvedor pode criar sua aplicação orientada a objetos e efetuar o mapeamento entre os objetos e o banco de dados e realizar a persistência de forma transparente, abstraindo toda a parte de representação de tipo de dados através de arquivos XML.

O NHibernate se torna o responsável por gerar o SQL necessário à sua aplicação, poupando o trabalho manual de programação da conversão dos dados relacionais para objetos.

Veja bem, o NHibernate não é a panacéia universal para resolver todos os problemas e conflitos existentes entre as aplicações orientada a objetos e o mundo dos banco de dados relacionais de forma que se você possui um banco de dados legado, sem regras de normalização definidas ou mesmo se você faz uso intenso de stored procedures e triggers o NHibernate não vai poder ajudá-lo; mas se você possui um banco de dados normalizado ou pretende desenvolver uma aplicação web usando o modelo MVC o NHibernate pode ser o seu salvador.

Feita esta pequena introdução vamos passar agora a dar mais detalhes sobre o NHibernate.

Qual o problema com o modelo relacional de banco de dados ?

Nem sempre o modelo relacional é equivalente ao modelo de objetos. Vejamos...

– O modelo normalizado mais eficiente geralmente tem menos tabelas que os objetos do modelo de objetos mais bem projetado;
– Existem objetos dependentes que são parte de um objeto maior (colunas de uma tabela);
– Existem objetos que são apenas visões de dados (dados de várias tabelas);
- O modelo relacional não suporta herança nem polimorfismo;
- No mundo relacional o critério de igualdade é a chave primária; no mundo OO (.NET) podemos ter igualdade de referência (verificado com ==) e  equivalência ( verificado com Equals());
- No mundo dos bancos de dados relacionais associações são representadas com chaves estrangeiras já em OO (.NET) representamos associações como referências ou coleções de referências para objetos; 

Uma boa ferramenta de ORM permite configurar essas incompatibilidades.

Quais as Vantagens em usar o NHiberante ?

O NHibernate pode ser usado com quais banco de dados ?

O NHibernate foi testado com o Microsoft SQL Server 2000 e também suporta os seguintes banco de dados:

Qual a arquitetura do NHibernate ?

Na figura abaixo temos uma representação resumida da arquitetura do NHibernate que é composta por interfaces:
(adaptado de: Hibernate com XML - Raphaela G. Fernanades e Gleydsonde A. F. Lima)

Assim temos as interfaces:

Session, Transaction e Query;
Interfaces responsáveis por executar operações de criação, deleção, consulta e atualização no banco de dados:

Configuration;
Interface utilizada pela aplicação para configurar o NHibernate:

Lifecycle e Validatable.:
 Interfaces responsáveis por realizar a interação entre os eventos do NHibernate e a aplicação: Interceptor,

 

Como funciona o mecanismo de persistência do NHibernate  ?

O NHibernate define três tipos de estados objetos:

  1. Transient (transientes) - São objetos que ainda não possuem uma representação no banco de dados ou que já foram excluídos;

  2. Persistent (persistentes) - São objetos que possuem uma representação no banco de dados;

  3. Detached (desligados) -  São objetos que possuem uma representação no banco de dados mas não possuem uma instância associada a uma sessão do NHibernate;

Para usar o mecanismo de persistência do Hibernate é preciso inicializar uma sessão.

A sessão oferece uma API de operações de persistência (gravação, leitura, transações).

Uma sessão é uma conexão com um banco de dados onde podemos realizar operações (consultas, inclusões, alterações, exclusões, etc.). Após a configuração do ambiente e do NHIbernate, abrimos uma sessão e realizamos operações com os objetos invocando métodos a partir do objeto Session. Veja abaixo os métodos usados:

Método Descrição
save(Object) Inclui um objeto em uma tabela do banco de dados;
saveOrUpdate(Object) Inclui um objeto na tabela caso ele ainda não exista  (seja transiente) ou atualiza o objeto caso ele já exista (seja persistente).
delete(Object) Apaga um objeto da tabela no banco de dados;
get(Class, Serializable id)

Retorna um objeto a partir de sua chave primária. A classe do objeto é passada como primeiro argumento e o seu identificador como segundo argumento;

Usando o NHibernate com o Visual Basic 2008 Express Edition

Neste artigo eu vou mostrar como criar uma aplicação MUITO simples que mostra como usar o NHibernate para fazer o mapeamento objeto relacional e persistir dados no SQL Server 2005 Express Edition.

Recursos necessários:

Roteiro de utilização:

1- Criando o banco de dados e a tabela

A primeira coisa a fazer é criar o banco de dados e a tabela no SQL Server 2005 Express, e, você pode fazer isso de diversas maneiras, para saber mais veja os meus artigos:

Vou criar o banco de dados TesteNHibernate e a tabela funcionario que terá a seguinte estrutura:

Neste nosso primeiro contato com NHibernate é importante manter as coisas o mais simples possível, desta forma foi criada a tabela funcionario contendo apenas 3 campos para facilitar a nossa vida.

2- Criação do projeto no VB 2008 Express e definição da referência ao NHibernate

Abra o VB 2008 Express Edition e no menu File-> New Project selecione o template Windows Forms e informe o nome da solução : usandoHibernate;

A seguir no formulário padrão inclua 3 controles Labels, 3 TextBox e um controle Button, conforme o leiaute abaixo:

Agora vamos definir a referência a API do NHibernate. Para isso você já deve ter baixado e descompactado os arquivos do NHibernate em uma pasta na sua máquina local.

Clique com o botão direito sobre o nome do projeto  e selecione : Add Reference;

A seguir selecione a guia Browse e procure pelo diretório onde você descompactou o NHibernate;

Navegue até a pasta net-2.0 e selecione as dlls desta pasta conforme a figura abaixo e clique no botão OK;

Com isso temos a referência a API do NHibernate e estamos prontos a usar os recursos por ele oferecidos.

3- Criação da classe e definição do domínio da aplicação

Nossa aplicação será muito simples pois teremos uma tabela chamada funcionario e uma classe chamada funcionario onde iremos definir as propriedades : codigo, nome e salario; (note que as propriedades possuem o mesmo nome dos campos da tabela)

Clique com o botão direito sobre o nome do projeto e selecione Add -> New Item, selecione o template Class e informe o nome funcionario.vb;

Agora inclua o seguinte código nesta classe:

Public Class funcionario
    Private _codigo As Int32
    Private _salario As Decimal
    Private _nome As String
    Public Sub New()
    End Sub
    Public Overridable Property Codigo() As Int32
        Get
            Return _codigo
        End Get
        Set(ByVal value As Int32)
            _codigo = value
        End Set
    End Property
    Public Overridable Property Nome() As String
        Get
            Return _nome
        End Get
        Set(ByVal value As String)
            _nome = value
        End Set
    End Property
    Public Overridable Property Salario() As Decimal
        Get
            Return _salario
        End Get
        Set(ByVal value As Decimal)
            _salario = value
        End Set
    End Property
End Class

Esta classe será usada no mapeamento com a tabela funcionario do banco de dados SQL Server 2005, ela implementa a entidade domínio do negócio.

O NHibernate trabalha associando cada tabela do banco de dados a uma classe POCO (Plain Old CLR Object) que são objetos .NET que contém apenas métodos gets e sets e um construtor padrão, dessa forma poderão ser instanciados pelo NHIbernate através da chamada Construtor.NewInstance().

É importante também definir um identificador único na classe , no caso a propriedade Codigo, de forma que todos os objetos persistentes possam ter um identificador único.

4- Criação e definição do arquivo de mapeamento que irá permitir mapear o objeto para a tabela do banco de dados

Vamos agora a um passo importante do roteiro e todo o cuidado é pouco para evitar erros que poderão tornar a sua vida em um inferno.

Clique com o botão direito sobre o nome do projeto e selecione Add -> New Item e em templates selecione Text File e informe o nome funcionario.hbm.xml;

A seguir inclua no arquivo funcionario.hbm.xml o seguinte código xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="usandoNHibernate.funcionario, usandoNHibernate" table="funcionario">
    <id name="Codigo" column="codigo" type="Int32">
      <generator class="assigned" />
    </id>
    <property name="Nome" column="Nome" type="String" length="15" />
    <property name="Salario" column="Salario" type="Int32" length="12" />
  </class>
</hibernate-mapping>

Após você incluir o código no arquivo você deve selecionar o arquivo e na janela de propriedades alterar a propriedade Build Action para Embedded Resource de forma a ser ser visível no projeto.

Todos os arquivos de mapeamento .hbm.xml sempre que importados para o projeto devem ter a sua propriedade Build Action definida como Embedded Resource.

 

Agora vamos entender o significado deste código deste arquivo:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">

Esta linha indica o inicio do mapeamento(hibernate-mapping) feito NHibernate e deve ser usada na versão 2.01(rn:nhibernate-mapping-2.2). (Se você estiver usando uma versão anterior não use esta sintaxe)

<class name="usandoNHibernate.funcionario, usandoNHibernate" table="funcionario">

Aqui definimos o nome da classe na tag class : class name="usandoNHibernate.funcionario, usandoNHibernate"   (Note que incluímos o nome do Assembly )

o atributo name deve conter o namespace e o nome do Assembly.

o atributo table deve indicar o nome da tabela : table="funcionario"   (se o nome da tabela for igual ao da classe não precisa ser declarado)

<id name="Codigo" column="codigo" type="Int32">
      <generator class="assigned" />
</id>

Nesta definição temos o mapeamento da chave primária onde a propriedade Codigo é mapeada para a coluna da tabela codigo.

A tag id identifica a chave primária e o atributo name="Codigo" informa o nome do atributo da classe .NET que se refere à chave primária da tabela.

O atributo column informa ao NHibernate que coluna na tabela é a chave primária, no caso codigo.

O atributo generator informa qual a estratégia para geração da chave primária. Para o nosso exemplo usamos a estratégia assigned que significa que iremos atribuir o valor a chave primária antes de persistir os objetos. Outros valores possíveis são:

  1. Increment - Lê o valor máximo da chave primária e incrementa;
  2. Identity - Mapeado para colunas identity no DB2, MySQL, MSSQL, SyBase, Informix;
  3. sequence - Mapeado em sequências no DB2, PostGreSQL, Oracle, SAP DB, Firebird;
  4. hilo - Usa um algoritmo high/low para gerar chaves únicas;
  5. uudi.hex - Usa uma combinação do IP com um timestamp para gerar um identificador único.
  6. guid - uUa o novo system.guid como identificador;

Após isso temos os mapeamentos das propriedades persistentes através da tag property.

 <property name="Nome" column="Nome" type="String" length="45" />
 <property name="Salario" column="Salario" type="Decimal" />

As tags property  indicam propriedades simples dos objetos onde o nome das propriedades das classes são definidos pelo atributo name, o tipo pelo atributo type e a coluna da tabela a que se refere pelo atributo column.

No nosso exemplo temos o mapeamento das propriedades Nome e Salario para as colunas Nome e Salario.

Se o atributo column não aparecer no mapeamento da propriedade, o NHibernate considera que a coluna na tabela do banco de dados a que se referencia possui o mesmo nome que o definido pelo atributo name.

Para você ter uma idéia abaixo temos a figura que representa o mapeamento de objetos do tipo funcionario para a tabela funcionario:

instância de objeto funcionario e tabela funcionario

Resumindo:

5 - Criação do arquivo de configuração do NHibernate que define o banco de dados usado, o provedor, etc.;

Vamos agora definir o arquivo de configuração do NHibernate que informa onde ele deve buscar e persistir as informações. Vamos usar o arquivo app.config e criar uma seção de configuração da aplicação. Abra o arquivo app.config ou crie um arquivo texto e altere o seu nome para app.config e a seguir inclua o seguinte código no arquivo:

Nota: Podemos também usar um arquivo de configuração chamado NHibernate.cfg.xml ao invés de usar o app.config.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
      <section name="hibernate-configuration"
      type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate"/>
  </configSections>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
       <property name="connection.provider">
            NHibernate.Connection.DriverConnectionProvider
       </property>
       <property name="dialect">
            NHibernate.Dialect.MsSql2005Dialect
       </property>
       <property name="connection.driver_class">
            NHibernate.Driver.SqlClientDriver
       </property>
       <property name="connection.connection_string">
           Data Source=.\SQLEXPRESS;Integrated Security=True; initial catalog=TesteNHibernate
       </property>
    </session-factory>
  </hibernate-configuration>
</configuration>

No arquivo acima definimos o provedor de acesso a base de dados SQL Server 2005 :  NHibernate.Dialect.MsSql2005Dialect .

A seguir alguns NHibernate SQL dialects:

Definimos também a string de conexão usada:   Data Source=.\SQLEXPRESS;Integrated Security=True; initial catalog=TesteNHibernate

Nota: NHibernate usa log4net para registrar o que está acontecendo internamente. Em uma aplicação em produção é recomendável configurar o log4net e ajustar NHibernate ao nível apropriado do registro para seu cenário.

Lembrete:

6 - Utilização da API do NHibernate para mapear os objetos e persistir os dados na tabela;

Finalmente estamos prontos para usar a API do NHibernate pois já temos criados todos os recursos necessários. Vamos lá...

No formulário form1.vb vamos definir os namespaces do NHibernate:

Imports NHibernate

Imports NHibernate.Cfg

Imports log4net

Imports System.Configuration

Imports NHibernate.Connection

Imports Iesi.Collections

No evento Click do botão Ok vamos incluir o código abaixo:

Private Sub btnSalvar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

 

Dim mConfig As New Configuration

 

'definindo o assembly para carregar os arquivo .hbm.xml  que fazem parte do mesmo

mConfig.AddAssembly("usandoNHibernate")

 

'definindo o dialeto do banco de dados

mConfig.SetProperty("hibernate.dialect", "NHibernate.Dialect.MsSql2005Dialect")

 

'criando uma sessao e iniciando uma transação

Dim mFactory As ISessionFactory = mConfig.BuildSessionFactory

Dim mSession As ISession = mFactory.OpenSession

Dim mTransaction As ITransaction = mSession.BeginTransaction

 

'criando um novo objeto funcionario

Dim funci As New funcionario

 

'obtendo os valores fornecidos no formulario

'e preenchendo o objeto

funci.Codigo = txtCodigo.Text

funci.Nome = txtNome.Text

funci.Salario = txtSalario.Text

 

'persistindo o objeto no banco de dados

mSession.Save(funci)

mTransaction.Commit()

mSession.Close()

 

MsgBox("Dados do objeto funcionário foram persistidos com sucesso na tabela : funcionario.")

 

End Sub

 

A arquitetura do NHibernate é formada por um conjunto de interfaces dentre as quais as principais são:

O objeto Configuration recupera através do Assembly todos os arquivos que terminam com ".hbm.xml" qual o utilizará para efetuar as manipulações.

O objeto de ISession representa uma conexão com a sua base de dados e o objeto ITransaction representa uma transação controlada também pelo NHibernate.

Executando o programa e informando alguns dados no formulário ao acionar o botão OK iremos persistir os dados do objeto funcionario na tabela:

E dessa forma acabamos de mapear e persistir objetos em um banco de dados relacional usando NHibernate.

Podemos ir além e mostrar como obter um objeto a partir do seu identificador e também como obter uma lista de objetos. Vamos por partes:

a- Obtendo um objeto a partir do seu identificador

Inclua um novo botão de comando (btnCarregar) no formulário e no seu evento Click vamos incluir o código abaixo:

Private Sub btnCarregar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCarregar.Click

 

'definindo o assembly para carregar os arquivo .hbm.xml ÿque fazem parte do mesmo

mConfig.AddAssembly("usandoNHibernate")

'definindo o dialeto do banco de dados

mConfig.SetProperty("hibernate.dialect", "NHibernate.Dialect.MsSql2005Dialect")

'criando uma sessao e iniciando uma transa‡Æo

Dim mFactory As ISessionFactory = mConfig.BuildSessionFactory

Dim mSession As ISession = mFactory.OpenSession

Dim mTransaction As ITransaction = mSession.BeginTransaction

 

Dim f As funcionario = DirectCast(mSession.Load(GetType(funcionario), 1), funcionario)

 

txtCodigo.Text = f.Codigo

txtNome.Text = f.Nome

txtSalario.Text = f.Salario

 

mSession.Flush()

'fecha a transa‡Æo e a sessÆo

 

mTransaction.Commit()

mSession.Close()

End Sub

A linha de código nova esta destacada e nela estamos obtendo um objeto funcionario a partir do seu identificador , no caso o Codigo igual a 1, logo iremos obter o primeiro objeto persistido.

Estamos usando o método Load do objeto Session no qual informamos o tipo de objeto e o identificador do objeto.

Na tabela funcionario recuperamos o registro com código igual a 1 que esta mapeado para o objeto funcionario e preenchemos o objeto funcionário com os dados para em seguida exibir os valores no formulário.  O identificador usado também é a chave primária da tabela funcionario.

Executando o programa iremos obter:

b- Obtendo uma lista de objetos

Vamos incluir no formulário form1.vb um controle ListBox (lstFuncionario) e um botão de comando (btnListar).

Em seguida inclua no evento Click do botão o seguinte código:

Private Sub btnListar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnListar.Click

 

'definindo o assembly para carregar os arquivo .hbm.xml ÿque fazem parte do mesmo

mConfig.AddAssembly("usandoNHibernate")

 

'definindo o dialeto do banco de dados

mConfig.SetProperty("hibernate.dialect", "NHibernate.Dialect.MsSql2005Dialect")

 

'criando uma sessao e iniciando uma transa‡Æo

Dim mFactory As ISessionFactory = mConfig.BuildSessionFactory

Dim mSession As ISession = mFactory.OpenSession

Dim mTransaction As ITransaction = mSession.BeginTransaction

 

Dim listaFuncionarios As IList = mSession.CreateCriteria(GetType(funcionario)).List()

 

For Each f As funcionario In listaFuncionarios

     lstFuncionarios.Items.Add(f.Codigo & " - " & f.Nome & " - " & f.Salario)

Next

 

'fecha a transa‡Æo e a sessÆo

mTransaction.Commit()

mSession.Close()

End Sub

 

No código em destaque estamos consulta a tabela e obtendo uma coleção de objetos ( System.Collections.IList).

Para isso estamos usando o recurso de consultas do NHibernate chamado Criteria.

A interface NHibernate.ICriteria representa uma consulta contra uma classe persistente e a sessão é a fábrica de instâncias para ICriteria.

No exemplo obtemos uma lista de objetos funcionários e listamos os seus valores em um controle ListBox.

Abaixo vemos o resultado da execução deste código:

Vou encerrando aqui esta pequena introdução sobre NHibernate, onde procurei apresentar os fundamentos de como usar o NHibernate com o Visual Basic 2008.

Como foi um artigo introdutório eu não entrei em detalhes em muitos recursos que a ferramenta possui , voltarei ao assunto em futuros artigos. Aguardem...

O NHibernate é uma ferramenta poderosa que você pode usar em suas aplicações .NET quer usando VB .NET ou C#. Para saber mais detalhes consulte o manual de referência no site : http://www.hibernate.org/343.html

Pegue o projeto completo aqui: usandoNHibernate.zip (removi as dlls do NHibernate e do Log4net)

Obs: para saber mais sobre mapeamento objeto relacional consulte a seção LINQ.

Existe uma ferramenta que pode ser usada para gerar os arquivos de mapeamentos .hbml de forma automática chamada MyGeneration, veja o link : http://www.mygenerationsoftware.com/portal/default.aspx

Até mais ver...

referências:


José Carlos Macoratti