Mapeamentos com Fluent NHibernate

Vamos dar sequência em nossa série sobre Fluent NHibernate

  1. Começando com Fluent NHibernate
  2. Mapeamentos com Fluent NHibernate
  3. Usando o Fluent NHibernate
  4. Gerando arquivos HBM
  5. Gerar arquivo SQL do mapeamento
  6. Configurando Log4NET
  7. Como funciona o Lazy Load

Nessa segunda etapa vamos criar os mapeamentos entre nossas entidades, para isso vamos seguir o diagrama de classe abaixo:

OBS: Esse diagrama é somente didático para exemplificar os mapeamentos usando o Fluent NHibernate

Criando as Entidades

Classe Departamento

A classe Departamento tem uma relação com a classe Pessoa de 1..*, por esse motivo na classe Departamento criamos uma lista de Pessoas

[sourcecode language=”csharp”]
public class Departamento
{
public virtual int Codigo { get; set; }
public virtual string Nome { get; set; }
public virtual string Descricao { get; set; }
public virtual DateTime DataCadastro { get; set; }
public virtual IList<Pessoa> Pessoas { get; set; }

public Departamento()
{
this.Pessoas = new List<Pessoa>();
}
}
[/sourcecode]

Classe Grupo

A classe Grupo também tem uma relação com a classe Pessoa de 1..*, por esse motivo na classe Grupo também criamos uma lista de Pessoas

[sourcecode language=”csharp”]
public class Grupo
{
public virtual int Codigo { get; set; }
public virtual string Nome { get; set; }
public virtual string Descricao { get; set; }
public virtual DateTime DataCadastro { get; set; }
public virtual IList<Pessoa> Pessoas { get; set; }

public Grupo()
{
this.Pessoas = new List<Pessoa>();
}
}
[/sourcecode]

Classe Status

A classe Status é bem simples, só possui os enumeradores

[sourcecode language=”csharp”]
public enum Status
{
Ativo = 1,
Inativo = 2,
Bloqueado = 3
}
[/sourcecode]

Classe Telefone

A classe Departamento tem uma relação com a classe Pessoa de 0..1, por esse motivo na classe Telefone criamos uma refência para a classe Pessoa

[sourcecode language=”csharp”]
public class Telefone
{
public virtual int Codigo { get; set; }
public virtual int CodigoDdd { get; set; }
public virtual int Numero { get; set; }
public virtual Pessoa Pessoa { get; set; }
}
[/sourcecode]

Classe Pessoa

A classe Pessoa é a classe que tem mais depedências

  1. Relação com a classe Status
  2. Relação de 0..1 com a classe Departamento
  3. Relação de 1..* com a classe Grupo
  4. Relação de 1..* com a classe Telefone

[sourcecode language=”csharp”]
public class Pessoa
{
public virtual int Codigo { get; set; }
public virtual string Nome { get; set; }
public virtual string Endereco { get; set; }
public virtual string Cep { get; set; }
public virtual string Email { get; set; }
public virtual DateTime DataCadastro { get; set; }

public virtual Status Status { get; set; }
public virtual Departamento Departamento { get; set; }
public virtual IList<Grupo> Grupos { get; set; }
public virtual IList<Telefone> Telefones { get; set; }

public Pessoa()
{
this.Grupos = new List<Grupo>();
this.Telefones = new List<Telefone>();
}
}
[/sourcecode]

Classe PessoaFisica

A classe PessoaFisica apenas herda da classe pai Pessoa

[sourcecode language=”csharp”]
public class PessoaFisica : Pessoa
{
public virtual string Cpf { get; set; }
public virtual string Nacionalidade { get; set; }
}
[/sourcecode]

Classe PessoaJuridica

A classe PessoaJuridica apenas herda da classe pai Pessoa

[sourcecode language=”csharp”]
public class PessoaJuridica : Pessoa
{
public virtual string Cnpj { get; set; }
public virtual string WebSite { get; set; }
}
[/sourcecode]

Até nesse momento não foi feito nenhum mapeamento, somente programação orientado a objetos

OBS 1: Note que todos nossos atributos estão como virtual, isso ocorre porque o NHibernate precisa para ler os atributos

OBS 2: Note que todas nossas listas estamos inicilizando no contrutor

Criando os Mapeamentos

Tipos de mapeamentos

  1. HasMany – one-to-many
  2. – Quando tem um relacionamento uma para muitos

  3. HasManyToMany – many-to-many
  4. – Quando tem um relacionamento muitos para muitos

  5. References – many-to-one
  6. – Quando tem um relacionamento muitos para um

Para criar os mapeamentos temos que prestar atenção em alguns aspectos:

  1. Por padrão para cada entidade, temos uma classe Map (Ex: Pessoa -> PessoaMap)
  2. Nossas classe Map tem que herdar de ClassMap, SubClassMap
  3. A definição do mapeamento deve ficar no construtor da classe Map

Classe DepartamentoMap

[sourcecode language=”csharp”]
public class DepartamentoMap : ClassMap<Departamento>
{
public DepartamentoMap()
{
Id(x => x.Codigo).GeneratedBy.Identity();

Map(x => x.Nome)
.Not.Nullable()
.Length(255);

Map(x => x.Descricao)
.Length(255);

Map(x => x.DataCadastro)
.Not.Nullable();

HasMany(m => m.Pessoas);
}
}
[/sourcecode]

Linha 1: Veja que nossa classe DepartamentoMap está herdando de ClassMap

Linha 5: Veja que estamos gerando a nossa chave primária com a função Id, onde será um identity

Linha 7: Mapeamos o campo Nome e configuramos que esse campo será NotNull e possui um tamanho de 255

Linha 17: Aqui usamos a função HasMany para configurar que a entidade Departamento tem uma referência de um para muitos com a entidade Pessoa

Classe GrupoMap

[sourcecode language=”csharp”]
public class GrupoMap : ClassMap<Grupo>
{
public GrupoMap()
{
Id(x => x.Codigo).GeneratedBy.Identity();

Map(x => x.Nome)
.Not.Nullable()
.Length(255);

Map(x => x.Descricao)
.Length(255);

Map(x => x.DataCadastro)
.Not.Nullable();

HasManyToMany(x => x.Pessoas);
}
}
[/sourcecode]

Linha 17: Aqui estamos usando outra função HasManyToMany para configurar que a entidade Grupo tem uma referência de muitos para muitos com a entidade Pessoa

Classe TelefoneMap

[sourcecode language=”csharp”]
public class TelefoneMap : ClassMap<Telefone>
{
public TelefoneMap()
{
Id(x => x.Codigo).GeneratedBy.Identity();

Map(x => x.CodigoDdd)
.Not.Nullable()
.Length(255);

Map(x => x.Numero)
.Not.Nullable();

References(x => x.Pessoa);
}
}
[/sourcecode]

Linha 14: Aqui usamos a função References para configurar a entidade Telefone tem uma refência de com a entidade Pessoa

Classe PessoaMap

[sourcecode language=”csharp”]
public class PessoaMap : ClassMap<Pessoa>
{
public PessoaMap()
{
Id(x => x.Codigo)
.GeneratedBy.Identity();

Map(x => x.Nome)
.Not.Nullable()
.Length(255);

Map(x => x.Endereco)
.Length(255);

Map(x => x.Cep)
.Length(255);

Map(x => x.Email)
.Length(255);

Map(x => x.DataCadastro)
.Not.Nullable();

Map(x => x.Status)
.CustomType<int>();

References(x => x.Departamento)
.Not.Nullable();

HasManyToMany(x => x.Grupos);

HasMany(x => x.Telefones).Cascade.All();
}
}
[/sourcecode]

Linha 24: Usamos um CustomType para mapear o tipo Enum

LInha 27: Aqui usamos a função References para configurar a entidade Pessoa possui uma refência com a entidade Departamento

Linha 30: Aqui estamos usando a função HasManyToMany para configurar que a entidade Pessoa tem uma referência de muitos para muitos com a entidade Grupos

Linha 32: Aqui usamos a função HasMany para configurar que a entidade Pessoa tem uma referência de um para muitos com a entidade Telefone. Também estamos usando a opção cascade que quando deletar uma pessoa vamos deletar seus telefones

Classe PessoaFisicaMap

[sourcecode language=”csharp”]
public class PessoaFisicaMap : SubclassMap<PessoaFisica>
{
public PessoaFisicaMap()
{
Map(x => x.Cpf)
.Not.Nullable()
.Length(14);

Map(x => x.Nacionalidade)
.Length(255);
}
}
[/sourcecode]

Linha 1: Como a classe PessoaFisica herda de Pessoa, em nosso mapeamento tem os que herdar de SubclassMap

Classe PessoaJuridicaMap

[sourcecode language=”csharp”]
public class PessoaJuridicaMap : SubclassMap<PessoaJuridica>
{
public PessoaJuridicaMap()
{
Map(x => x.Cnpj)
.Not.Nullable()
.Length(18);

Map(x => x.WebSite)
.Length(255);
}
}
[/sourcecode]

Linha 1: Como a classe PessoaJuridica herda de Pessoa, em nosso mapeamento tem os que herdar de SubclassMap

Gerando o banco

Agora para ver se todo nosso mapeamento esta correto, vamos gerar o nosso banco a partir dos mapeamentos

Veja o código abaixo:

[sourcecode language=”csharp”]
public static void CriarTabelasBanco()
{
FluentConfiguration configuration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(x => x.FromConnectionStringWithKey("ConexaoBanco")).ShowSql())
.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true,true))
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<Pessoa>());

configuration.BuildSessionFactory();
}
[/sourcecode]

Linha 3: Iniciamos a classe de configuração do Fluent

Linha 4: Configurações para base de dados (Banco, String de conexão)

Linha 5: Para executar nosso mapeamento no banco, temos que instanciar a classe SchemaExport e executar o método Create

Linha 6: Temos que dizer onde esta os nossos mapeamentos, não precisa adicionar todos as entidades, apenas uma, dessa forma o Fluent ja sabe onde está o assembly com os mapeamentos

Linha 8: Executamos a configuração

Veja o resultado na imagem abaixo:

Atenção:

veja que foi criada uma tabela para o mapeamento ManyToMany chamada GruposToPessoas

Download do projeto

Em nosso próximo post vamos começar a criar os CRUDs para ver se nossos mapeamentos estão corretos

Deixe seu comentário, opinião, critica

Aquele abraço!

Sobre Leandro Prado

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