ASP NET MVC + NHibernate + ExtJs – Parte 2

Seguindo o nosso tutorial para criar um sistema de Controle de Contatos, hoje vamos criar nossas entidades e mapear usando o NHibernate.

Veja abaixo o diagrama de classe que vamos criar.

Antes de começar a criar as classes, podemos deletar a Class1.cs dos projetos Contatos.Factory e Contatos.Business, essa classe é criada automaticamente quando criamos um novo projeto e não vamos usa-las.

Nossas entidades devem ficar dentro da pasta Entity do projeto Contatos.Factory, para criar as classes clique com o botão direito em cima da pasta Entity e selecione a opção Add -> Class depois coloque o nome da classe Contato.cs.

Criando as classes

Após crie mais três classes uma com o nome Telefone.cs e outra TipoTelefone.cs e outra Grupo.cs, veja o conteúdo das classess abaixo:

Classe Contato

[sourcecode language=”csharp”]
namespace Contatos.Factory.Entity
{
using System;
using System.Collections.Generic;

///
/// Classe Contato
///
public class Contato
{
///
/// Gets or sets Codigo.
///
public virtual int Codigo { get; set; }

///
/// Gets or sets Nome.
///
public virtual string Nome { get; set; }

///
/// Gets or sets DataNascimento.
///
public virtual DateTime DataNascimento { get; set; }

///
/// Gets or sets Sexo.
///
public virtual char Sexo { get; set; }

///
/// Gets or sets Email.
///
public virtual string Email { get; set; }

///
/// Gets or sets WebSite.
///
public virtual string WebSite { get; set; }

///
/// Gets or sets Anotacoes.
///
public virtual string Anotacoes { get; set; }

/// <summary>
/// Gets or sets ListaTelefones.
/// </summary>
public virtual IList<Telefone> ListaTelefones { get; set; }

/// <summary>
/// Gets or sets ListaGrupos.
/// </summary>
public virtual IList<Grupo> ListaGrupos { get; set; }
}
}
[/sourcecode]

Classe Telefone

[sourcecode language=”csharp”]namespace Contatos.Factory.Entity
{
///
/// Classe Telefone
///
public class Telefone
{
///
/// Gets or sets Codigo.
///
public virtual int Codigo { get; set; }

///
/// Gets or sets CodigoDDD.
///
public virtual short CodigoDDD { get; set; }

///
/// Gets or sets Numero.
///
public virtual int Numero { get; set; }

///
/// Gets or sets Tipo.
///
public virtual TipoTelefone TipoTel { get; set; }

/// <summary>
/// Gets or sets Contato.
/// </summary>
public virtual Contato ContatoTelefone { get; set; }
}
}
[/sourcecode]

Classe TipoTelefone

[sourcecode language=”csharp”]namespace Contatos.Factory.Entity
{
///
/// Classe Tipo Telefone
///
public class TipoTelefone
{
///
/// Gets or sets Codigo.
///
public virtual int Codigo { get; set; }

///
/// Gets or sets Descricao.
///
public virtual string Descricao { get; set; }
}
}
[/sourcecode]

Classe Grupo

[sourcecode language=”csharp”]
namespace Contatos.Factory.Entity
{
using System.Collections.Generic;

/// <summary>
/// Classe grupo
/// </summary>
public class Grupo
{
/// <summary>
/// Gets or sets Codigo.
/// </summary>
public virtual int Codigo { get; set; }

/// <summary>
/// Gets or sets Nome.
/// </summary>
public virtual string Nome { get; set; }

/// <summary>
/// Gets or sets Descricao.
/// </summary>
public virtual string Descricao { get; set; }

/// <summary>
/// Gets or sets ListaContato.
/// </summary>
public virtual IList<Contato> ListaContatos { get; set; }
}
}
[/sourcecode]

Como podemos perceber todos nossos atributos foram declarados como virtual, isso porque o NHibernate necessita para conseguir gerar o mapeamento.

Depois de criadas todas as classes temos que criar os arquivos XML que serão responsáveis por mapear nossas propriedades com os campos no banco de dados, para criar os mapeamentos clique com o botão direito em cima da pasta Mappings e selecione a opção Add -> New Item depois selecione a opção XML File coloque o nome TipoTelefone.hbm.xml

Criar arquivo XML

O mapeamento para a classe TipoTelefone deverá ser feita da seguinte maneira:

[sourcecode language=”xml”]
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Contatos.Factory"
namespace="Contatos.Factory.Entity" >

<class name="TipoTelefone" table="tbTipoTelefone">

<id name="Codigo" access="property" column="cod_tipo_telefone" type="Int32">
<generator class="sequence">
<param name="sequence">tipo_telefone_seq_id</param>
</generator>
</id>

<property name="Descricao" not-null="true" access="property" type="String">
<column name="descricao" length="100" />
</property>

</class>

</hibernate-mapping>
[/sourcecode]

Entendendo o Mapeamento

  • assembly: Assembly (dll) onde se encontra nossas entidades
  • namespace: Nome do namespace onde se encontra nossas entidades
  • class: Aqui definimos que a nossa classe TipoTelefone será a tabela tbTipoTelefone no banco
  • id: É o campo chave (Primary Key) da tabela, que nesse caso será gerada por uma sequence
  • property: Cada propriedade da classe vai ser uma coluna da tabela no banco de dados

Agora vamos criar o mapeamento para a classe Telefone, adicione um novo arquivo XML dentro da pasta Mappings com o nome Telefone.hbm.xml

[sourcecode language=”xml”]
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Contatos.Factory"
namespace="Contatos.Factory.Entity" >

<class name="Telefone" table="tbTelefone">

<id name="Codigo" access="property" column="cod_telefone" type="Int32">
<generator class="sequence">
<param name="sequence">telefone_seq_id</param>
</generator>
</id>

<property name="CodigoDDD" not-null="true" access="property" type="Int16">
<column name="cod_ddd" />
</property>

<property name="Numero" not-null="false" access="property" type="Int32">
<column name="numero_telefone" />
</property>

<many-to-one name="ContatoTelefone" column="cod_contato" class="Contato" not-null="true"/>

<many-to-one name="TipoTel" column="cod_tipo_telefone" class="TipoTelefone" not-null="true"/>

</class>

</hibernate-mapping>

[/sourcecode]

Aqui podemos ver que temos um novo tipo de mapeamento many-to-one, ou seja, para cada Telefone podemos ter vários Tipos de Telefone que é a nossa classe TipoTelefone. A mesma coisa acontece para o ContatoTelefone onde cada Contato pode ter vários Telefones que é representada pela nossa classe Telefone. Resumindo estamos falando para o NHibernate como cada classe conversa com a outra.

Agora vamos mapear a classe Contato, adicione um novo arquivo com o nome Contato.hbm.xml

[sourcecode language=”xml”]
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Contatos.Factory"
namespace="Contatos.Factory.Entity" >

<class name="Contato" table="tbContato">

<id name="Codigo" access="property" column="cod_contato" type="Int32">
<generator class="sequence">
<param name="sequence">contato_seq_id</param>
</generator>
</id>

<property name="Nome" not-null="true" access="property" type="String">
<column name="nome" length="200" />
</property>

<property name="DataNascimento" not-null="true" access="property" type="DateTime">
<column name="data_nascimento" />
</property>

<property name="Sexo" not-null="true" access="property" type="Char">
<column name="sexo" length="1" />
</property>

<property name="Email" not-null="true" access="property" type="String">
<column name="email" length="100" />
</property>

<property name="WebSite" not-null="true" access="property" type="String">
<column name="web_site" length="100" />
</property>

<property name="Anotacoes" not-null="true" access="property" type="String">
<column name="anotacoes" length="300" />
</property>

<bag name="ListaTelefones" inverse="true" cascade="all-delete-orphan" lazy="true">
<key column="cod_contato" />
<one-to-many class="Telefone" />
</bag>

<bag name="ListaGrupos" table="tbContatoGrupo" cascade="none" lazy="false">
<key column="cod_contato" />
<many-to-many class="Grupo" column="cod_grupo" not-found="ignore" />
</bag>

</class>

</hibernate-mapping>
[/sourcecode]

Aqui podemos ver que temos um novo tipo de mapeamento many-to-many, criamos um bag que significa uma coleção (IList), que será nossa lista de Grupos, onde cada Contato pode estar em vários Grupos, com isso temos que criar uma tabela associativa chamada tbContatoGrupo que será responsável por esse controle.

Tipos de mapeamento para coleções

  • List: é uma lista de entidades ordenadas por um index e que pode conter itens duplicados, temos que mapear uma coluna de index (Usado com a interface IList<T>)
  • Set: é uma lista de entidades sem ordem, que NÃO pode conter itens duplicados
  • Bag: é uma lista de entidades sem ordem que pode conter itens duplicados (Usado com a interface IList<T>)

E por último o mapemanto para a classe grupo, adicione o novo arquivo com o nome Grupo.hbm.xml

[sourcecode language=”xml”]
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Contatos.Factory"
namespace="Contatos.Factory.Entity" >

<class name="Grupo" table="tbGrupo">

<id name="Codigo" access="property" column="cod_grupo" type="Int32">
<generator class="sequence">
<param name="sequence">grupo_seq_id</param>
</generator>
</id>

<property name="Nome" not-null="true" access="property" type="String">
<column name="nome" length="200" />
</property>

<property name="Descricao" not-null="true" access="property" type="String">
<column name="descricao" length="200" />
</property>

<bag name="ListaContatos" table="tbContatoGrupo" cascade="none" lazy="false">
<key column="cod_grupo" />
<many-to-many class="Contato" column="cod_contato" not-found="ignore" />
</bag>

</class>

</hibernate-mapping>
[/sourcecode]

Aqui observamos que temos o mapeamento many-to-many novamente, só que a lógica aqui inverte, ou seja, para cada Grupo podemos ter vários Contatos.

Quando temos uma associação de muitos para muitos, que é o caso Contatos -> Grupos o mapemaneto tem que ser feita nas duas classes, para que a tabela associativa seja criada corretamente.

Depois que criamos todos os arquivos de mapeamento não podemos esquecer de maneira nenhuma de um detalhe alterar a propriedade Build Action para Embedded Resource, para cada arquivo XML clicar com o bortão direito e ir em Propriedades, depois alterar a propriedade Build Action para Embedded Resource

Nessa segunda parte vimos como mapear nossas entidades com o NHibernate, nosso próximo passo será configurar o NHibernate para conectar com o banco de dados.

Qualquer erro, dúvida, opinião favor entrar em contato!

Download Parte 2

Até a proxima!

Sobre Leandro Prado

Leandro Silveira Prado é Premier Field Engineer na Microsoft especializado em Application Lifecycle Management.