Desenvolvimento - C#

.NET: Guia Inicial do NHibernate

NHibernate é uma biblioteca (Framework) baseada em .NET para persistir os objetos para bases de dados relacionais. Baseado em uma ferramenta de persistência de dados do Java, chamado Hibernate, o NHibernate tem a finalidade de persistir os objetos .NET em uma base de dados relacional subjacente.

por Israel Aéce



O que é o NHibernate

NHibernate é uma biblioteca (Framework) baseada em .NET para persistir os objetos para bases de dados relacionais. Baseado em uma ferramenta de persistência de dados do Java, chamado Hibernate, o NHibernate tem a finalidade de persistir os objetos .NET em uma base de dados relacional subjacente. Isso facilita muito ao invés de escrever códigos SQL dentro e fora da base de dados, pois o NHibernate gera o código SQL necessário, certificando-se que os tipos e o valores são corretamente criados.

Por que este Guia

Todas as pessoas que já trabalharam com o Hibernate, não sentirão grandes dificuldades em utilizar o NHibernate no mundo .NET. Como os projetos são bastante similares, poderá utilizar a documentação do Hibernate e basear-se nela para aplicar na utilização do NHibernate.

Este artigo é tem a finalidade de mostrar os primeiros passos para a utilização do NHibernate. Cobrirá como persistir um objeto simples em uma tabela.

O Processo de Desenvolvimento

Brevemente o NHibernate terá ferramentas para ajudar na geração do schema da tabela, gerando e atualizando assim os arquivos de mapeamentos. Entretanto, estamos assumindo que não temos estas ferramentas e sendo assim, teremos que criar o arquivo de mapeamento (XML) entre a Classe .NET e a Tabela da Base de Dados manualmente. Abaixo os passos para o desenvolvimento:

  • 1. Criar a Tabela na Base de Dados.
  • 2. Criar a Classe .NET.
  • 3. Criar o Arquivo de Mapeamento.
  • 4. Criar o Arquivo de Configuração do NHibernate.
  • 5. Usar a API do NHibernate.

Passo 1: Escrevendo o SQL

O exemplo é algo bem simples. Considere que estamos desenvolvendo um subsistema básico de gerenciamento de usuários para um Web Site qualquer. O tabela chamará usuários (users) e estaremos assumindo que a Base de Dados a ser utilizada chama-se NHibernate:

1
2
3
4
5
6
7
8
9
10
11
12
USE NHibernate
GO
CREATE TABLE users (
LogonID nvarchar(20) NOT NULL default "0",
Name nvarchar(40) default NULL,
Password nvarchar(20) default NULL,
EmailAddress nvarchar(40) default NULL,
LastLogon datetime default NULL,
PRIMARY KEY (LogonID)
GO
)

Passo 2: Criando a Classe .NET

Necessitamos criar uma classe com as propriedades que desejamos persistir na Base de Dados. NHibernate utiliza Reflection para resgatar e atribuir os valores as propriedades dos objetos que queremos persistir. Veja abaixo uma classe simples que pode ser persistida utilizando NHibernate:

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
using System;
namespace CS
{
public class User
{
private string id;
private string userName;
private string password;
private string emailAddress;
private DateTime lastLogon;
public User(){}
private string Id
{
get { return id; }
set { id = value; }
}
private string UserName
{
get { return userName; }
set { userName = value; }
}
private string Password
{
get { return password; }
set { password = value; }
}
private string EmailAddress
{
get { return emailAddress; }
set { emailAddress = value; }
}
private DateTime LastLogon
{
get { return lastLogon; }
set { lastLogon = value; }
}
}
}

No exemplo acima, as propriedades e o construtor é definido como públicos, mas isso não é uma exigência para o NHibernate, podendo utilizar propriedades definidas como public, protected, internal ou mesmo private para persistir os dados.

Passo 3: Escrevendo o Arquivo de Mapeamento

Com a tabela criada na Base de Dados e a nossa Classe .NET também escrita, ainda necessitamos uma maneira de dizer ao NHibernate quais as propriedades da Classe .NET que receberá as informações das colunas da tabela da Base de Dados. Isto é realizado através de um arquivo de mapeamento, escrito em formato XML, tendo cada classe seu respectivo arquivo XML de mapeamento.

Para que o sistema funcione corretamente, você deve nomear o arquivo de mapeamento com o mesmo nome da classe, ficando da seguinte forma: "Objeto.hbm.xml", e no nosso caso: "User.hbm.xml". Além disso, é necessário colocá-lo no mesmo diretório da classe, pois com isso o NHibernate fará as coisas com mais facilidade. Abaixo um exemplo do arquivo de mapeamento:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="CS.User, CS" table="users">
<id name="Id" column="LogonId" type="String" length="20">
<generator class="assigned" />
</id>
<property name="UserName" column= "Name" type="String" length="40"/>
<property name="Password" type="String" length="20"/>
<property name="EmailAddress" type="String" length="40"/>
<property name="LastLogon" type="DateTime"/>
</class>
</hibernate-mapping>

Analisando o código acima, o que mais nos chama a atenção são as tags class e table, onde definimos o nome da Classe e o nome da Tabela da Base de Dados de onde será recuperado e/ou inserido os dados. No caso de nosso exemplo, estamos mapeando os dados da tabela "users" para a classe "User". Logo mais abaixo temos as propriedades que compõem nosso objeto. Internamento o NHibernate varre este arquivo recuperando os atributos "name", que correspondem as propriedades da nossa Classe User. É recuperado também o atributo "column", que se refere a coluna correspondente na Base de Dados, lembrando que este atributo é opcional, e quando ocultado o NHibernate assume que o nome da coluna na Base de Dados é o mesmo da Propriedade.

A tag Id é a responsável por ser a chave identificadora do objeto/registro, onde mapeamos a propriedade (name) para a coluna da Base de Dados (column). No nosso exemplo, geramos as nossas próprias chaves, não necessitando que a Base de Dados gere automaticamente, mas isso é perfeitamente possível. Para saber um pouco mais sobre chaves, poderá consultar a documentação do NHibernate.

Observação: Se você estiver utilizando Visual Studio .NET, certifique-se que ao compilar o projeto a propriedade Build Action dos arquivos XML de mapeamento - que no nosso caso chama-se "User.hbm.xml" - está definido como "Embedded Resource", para que o arquivo XML faça parte do Assembly como Resource. Isso facilita porque não há a necessidade de distribuir os arquivos XML de mapeamento juntos com a aplicação, mas claro, a desvantagem é que se mudar o arquivo de mapeamento, a aplicação deverá ser recompilada.

Passo 4: Criando o Arquivo de de Configuração para a Base de Dados

Ainda falta dizermos ao NHibernate onde ele deverá ir buscar e persistir os dados. A maneira mais fácil e simples é criando uma seção de configuração dentro do arquivo de configuração da aplicação (Web.Config ou App.Config). Isto é equivalente a usar as propriedades de configuração do NHibernate. Abaixo veremos como criar a seção de configuração dentro do arquivo App.Config:

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
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="nhibernate"
type="System.Configuration.NameValueSectionHandler, System,
Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>
<nhibernate>
<add
key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"
/>
<add
key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect"
/>
<add
key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"
/>
<add
key="hibernate.connection.connection_string"
value="CONNECTION_STRING"
/>
</nhibernate>
</configuration>

No código acima, definimos o SqlClient como Provider para acesso à Base de Dados SQL Server 2000. A ConnectionString foi ocultada apenas para não confundir o leitor, tendo que ser definida com os dados de acesso do servidor de Banco de Dados que estará servindo a aplicação.

Veja não existe nenhuma informação sobre a configuração do log4net. NHibernate usa log4net para registrar o que está acontecendo internamente. Em uma aplicação em produção é recomendável configurarar o log4net e ajustar NHibernate ao nível apropriado do registro para seu cenário.

Passo 5: Utilizando o NHibernate

Até agora fizemos o trabalho árduo. Se tudo ocorreu como esperamos, até o momento temos:

  • Arquivo User.cs - Classe .NET do nosso objeto.
  • Arquivo User.hbm.xml - Arquivo XML de mapeamento.
  • app.Config - Arquivo de Configuração da aplicação.
  • SQL Server - A Tabela "users" criada.
Abaixo os passos que devemos seguir para utilizar o NHibernate para recuperar e inserir os dados na Base de Dados:

  • 1. - Criar o Objeto de Configuração.
  • 2. - Informar ao Objeto de Configuração os tipos de Objeto que deseja persistir.
  • 3. - Criar uma sessão com a Base de Dados.
  • 4. - Carregar, Salvar e Consultar seus objetos.
  • 5. - Fechar ou Flush() na sessão com a Base de Dados.

Abaixo veremos como utilizar o NHibernate:

Inicialmente devemos criar o objeto de configuração do NHibernate que é responsável e tem o conhecimento sobre todos os mapeamentos que existem entre os objetos do nosso sistema e a Base de Dados.

1
2
Configuration cfg = new Configuration();
cfg.AddAssembly("CS");

O objeto de Configuração recupera através do Assembly todos os arquivos que terminam com ".hbm.xml" qual o utilizará para efetuar as manipulações. Existem outras formas de definir e carregar os arquivos de mapeamentos, mas esta é a forma mais simples.

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

1
2
3
ISessionFactory factory = cfg.BuildSessionFactory();
ISession session = factory.OpenSession();
ITransaction transaction = session.BeginTransaction();

Depois das configurações realizadas, nos resta definitivamente inserir, carregar e consultar a Base de Dados através do NHibernate:

1
2
3
4
5
6
7
8
9
10
11
User newUser = new User();
newUser.Id = "joe_cool";
newUser.UserName = "Joseph Cool";
newUser.Password = "abc123";
newUser.EmailAddress = "joe@cool.com";
newUser.LastLogon = DateTime.Now;
session.Save(newUser);
transaction.Commit();
session.Close();

Como podemos ver no código acima, um novo objeto do tipo User é criado, definimos as suas propriedades e depois o passamos para o método Save(...) do NHibernate, que baseando-se no arquivo XML de mapeamento correspondente, faz a persistência do objeto de forma "mágica" na nossa Base de Dados.

Para recuperar um objeto da Base de Dados, utilize o método Load, passando o ID do usuário para carregarmos o objeto e assim manipulá-lo. Exemplo:

1
2
3
4
5
6
session = factory.OpenSession();
User joeCool = (User)session.Load(typeof(User), "joe_cool");
joeCool.EmailAddress = "tt@tt.com";
session.Flush();

Depois de recuperado o Usuario com o Id "joe_cool" da Base de Dados, alteramos o E-Mail do mesmo para "tt@tt.com" e invocamos o método Flush() da Session para persistir/devolver os dados atualizados na Base de Dados.

Podemos também recuperar uma lista de objetos da nossa Base de Dados através do NHibernate. Utilizamos a Interface IList para isto, qual encontra-se dentro do Namespace System.Collections. Um exemplo simples seria algo como:

1
2
3
4
5
6
session = factory.OpenSession();
IList userList = session.CreateCriteria(typeof(User)).List();
foreach(User user in userList)
Console.WriteLine(user.Id + " último login em " + user.LastLogon);

CONCLUSÃO: Bem, como vimos neste artigo, a utilização de um OR/M (Object Relational/Mapping) como o NHibernate diminui e muito o grande espaço que existe entre as tabelas de um Banco de Dados relacional e os objetos de uma aplicação. É ótimo para quando se trabalha com uma aplicação fortemente Orientada à Objetos.

Agradecimentos: Gostaria de agradecer ao meu amigo Mike Doerfler, que gentilmente cedeu o artigo (A Quick Start Guide to NHibernate), para que o conteúdo do artigo escrito por ele, seja adaptado e traduzido para a língua portuguesa.

Referências:

Artigo desenvolvido utilizando:

* Visual Studio .NET 2003
* .NET Framework 1.1
* SQL Server 2000
* NHibernate - Versão Alpha
* Windows XP Professional

Clique aqui para fazer Download do Código.
Israel Aéce

Israel Aéce - Especialista em tecnologias de desenvolvimento Microsoft, atua como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. Como instrutor Microsoft, leciona sobre o desenvolvimento de aplicações .NET. É palestrante em diversos eventos Microsoft no Brasil e autor de diversos artigos que podem ser lidos a partir de seu site http://www.israelaece.com/. Possui as seguintes credenciais: MVP (Connected System Developer), MCP, MCAD, MCTS (Web, Windows, Distributed, ASP.NET 3.5, ADO.NET 3.5, Windows Forms 3.5 e WCF), MCPD (Web, Windows, Enterprise, ASP.NET 3.5 e Windows 3.5) e MCT.