Olá caros leitores! Depois de muito tempo(devido a correria) estou postando a segunda parte do “Criando uma pequena aplicacao usando nhibernate”.
Na segunda parte fiz uma pequena aplicação em windows form, o qual usa a arquitetura definida na parte 1. Fiz a aplicação com um basico de MVC,para assim separar as responsabilidade de cada objeto. Nesse post não vou colocar o código do windows form, somente as interfaces. Ao finaldesta página você pode baixar o código-fonte da aplicação.
O Que Mudou Na Arquitetura Definida Anteriormente
Antes de explicar como funciona o MVC da aplicação vou mostrar algumas alterações que fiz na arquitetura.
Nova classe criada:
UtilitarioDeData.cs
using System;
namespace PrimeraAplicacaoNHibernate.Util
{
public class UtilitarioDeData
{
private const string FormatoBrasileiro = "{0:MM/dd/yyyy}";
public static DateTime ConvertaParaBanco(string dataString)
{
return Convert.ToDateTime(dataString);
}
public static string ConvertaParaFormatoBrasileiro(DateTime data)
{
return String.Format(FormatoBrasileiro, data);
}
}
}
Categoria.cs
public class Categoria
{
//Restante da propriedades
public override string ToString()
{
return Descricao;
}
}
Na classe Categoria, sobreescrevi o metodo ToString() com a finalidade de imprimir a descrição da mesma na hora da listagem.
Pessoa.cs
public class Pessoa
{
//Restante da propriedades
public virtual string ObtenhaDataNascimentoFormatada()
{
//UtilitarioDeData é uma classe que fica com a responsabilidade de converter a data. Seja ela de banco para formato brasileiro e vice-versa
return UtilitarioDeData.ConvertaParaFormatoBrasileiro(DataNascimento);
}
public override string ToString()
{
var texto = new StringBuilder();
texto.AppendFormat("{0} {1} - ", Nome, SobreNome)
.AppendFormat("{0} - ", ObtenhaDataNascimentoFormatada())
.AppendFormat("{0} - ", Sexo ? "Masculino": "Feminino")
.AppendFormat("{0}", Categoria.Descricao);
return texto.ToString();
}
}
Em Pessoa, também sobreescrevi o ToString() com a mesma finalizade da classe Categoria, e adicione o método ObtenhaDataNascimentoFormatada() para retornar da data de nascimento da pessoa no formato brasileiro.
Pessoa.hbm.xml
<many-to-one name="Categoria" class="PrimeraAplicacaoNHibernate.Dominio.Categoria"
column="categoria_id" cascade="none" lazy="false"/>
No mapeamento do atributo Categoria contido em Pessoa adicionei a propriedade lazy=”false”, pois caso contrário lançaria exception LazyInitializationException ao acessar o ToString().
Veja bem, fazer lazy=”false” não é a solução de todos os problemas, isso pode impactar na questão de desempenho!
Este post não tem seu foco em desempenho, para isso vejo o artigo NHibernate Best Practices with ASP.NET(en).
IRepositorioCategoria.cs
public interface IRepositorioCategoria
{
//Restante dos outros métodos
bool PodeSerRemovida(Categoria categoria);
}
Esse novo método verifica se uma categoria está associada a uma pessoa. Se a categoria estiver associada, ela não pode ser removida.
RepositorioCategoria.cs
public class RepositorioCategoria : IRepositorioCategoria
{
//Restante do código
public bool PodeSerRemovida(Categoria categoria)
{
var hql = new StringBuilder();
long resultado;
hql.AppendFormat("select count(p) FROM {0} p ", typeof(Pessoa))
.AppendFormat("WHERE p.Categoria.Id = :categoriaId");
using (var session = NHibernateHelper.OpenSession())
{
resultado = (long)session.CreateQuery(hql.ToString())
.SetString("categoriaId", categoria.Id.ToString())
.UniqueResult();
}
return resultado > 0 ? false : true;
}
}
No Código acima criei um hql que verifica se tem alguma pessoa associada com a categoria que estou querendo remover.
IRepositorioPessoa.cs
public interface IRepositorioPessoa
{
//Restante dos outros métodos
ICollection<Pessoa> GetList();
}
RepositorioPessoa.cs
public class RepositorioPessoa : IRepositorioPessoa
{
//Restante do código
public ICollection<Pessoa> GetList()
{
using (var session = NHibernateHelper.OpenSession())
{
var pessoas = session.CreateCriteria(typeof(Pessoa)).List<Pessoa>();
return pessoas;
}
}
}
no repositório de pessoa adicionei o método que lista todas as pessoas cadastradas no banco.
Como funciona o MVC da aplicação
Bem, o MVC de uma forma resumida é uma métodologia(alguns o classificam como um padrão, para mim é uma métodologia), de como separar lógica de negócio da lógica de apresentação de uma aplicação que são:
- Modelo(Model)
- Visão(View)
- Controle(Controller)
Não vou aprofundar no MVC. Para mais informações leia aqui.
Na aplicação que fiz o MVC funciona da seguinte forma:

Temos o windows form que conhece o controlador, esse por sua vez conhece o repositorio que por final persiste os dados. Quando digo conhecer, é por meio de interface.
A aplicação em questão é composta de 3 telas:
- FormularioPrincipal
- FormularioDeCategoria
- FormularioDePessoa
Do FormularioPrincipal parte-se para as outras duas telas(FormularioDeCategoria e FormularioDePessoa).
Para reutilizar algumas coisas entre as telas, crie uma tela chamada FormularioBasico, nessa tela coloquei métodos que podem ser usado entre as outras telas.
FormularioBasico.cs
public partial class FormularioBasico : Form
{
public void MostreMensagemDeAtencao(string mensagem)
{
//Codigo
}
public void MostreMensagemDeErro(string mensagem)
{
//Mais código
}
}
As telas FormularioDeCategoria e FormularioDePessoa herdam de FormularioBasico.
Cada tela possui o seu próprio controlador. O FormularioPrincipal principal possui um controlador que implementa a interface IControladorDaTelaFormularioPrincipal,este recebe como parâmetro em seu construtor uma tela que implementa a interface IFormularioPrincipal(FormularioPrincipal implementa essa interface). O FormularioPrincipal é responsável por instanciar seu controlador.
IFormularioPrincipal.cs
public interface IFormularioPrincipal
{
void MostreTelaDeCategoria();
void MostreTelaDePessoa();
}
A interface é usada para o controlador saber o que ele pode dizer para a tela fazer.
FormularioPrincipal.cs
public partial class FormularioPrincipal : Form, IFormularioPrincipal
{
private readonly IControladorDaTelaFormularioPrincipal _controlador;
public FormularioPrincipal()
{
_controlador = new ControladorDaTelaFormularioPrincipal(this);
}
//Restante do código da tela
}
Bem, com o controlador instanciado, qualquer interação que o usuário faça com a tela, este deverá ser passado para o controlador, pois a tela é burra e não toma decisões. O responsável por isso é o controlador. Para a tela comunicar como controlador, ela faz uso dos método declarado na interface do controlador.
IControladorDaTelaFormularioPrincipal.cs
public interface IControladorDaTelaFormularioPrincipal
{
void UsuarioClicouNoBotaoDeCategoria();
void UsuarioClicouNoBotaoDePessoa();
}
Abaixo a implementação da interface.
ControladorDaTelaFormularioPrincipal.cs
public class ControladorDaTelaFormularioPrincipal : IControladorDaTelaFormularioPrincipal
{
private readonly IFormularioPrincipal _tela;
public ControladorDaTelaFormularioPrincipal(IFormularioPrincipal tela)
{
_tela = tela;
}
}
O fluxo de comunicação entre tela e controlador fica: Usuario interage com a tela, tela avisa ao controlador o que o usuário fez, por final o controlador decide o que fazer e como e tela deve ser comportar. No caso do FormularioPrincipal não há necessidade de consulta a banco, mas para as telas FormularioDeCategoria e FormularioDePessoa pode haver a necessidade do controlador usar o repositório para fazer alguma operação envolvendo banco.
Um fluxo básico seria: Ao abri a tela FormularioDeCategoria logo após instanciar o controlador e executar o InitializeComponent(), a tela avisa ao controlador que ele deve se inicializar. No estado de inicialização o controlador avisa a tela que ela deve limpar o elemento de listagem de itens, logo em seguida o controlador usa o repositório para obter a lista de Categorias do banco, e ao obter essa lista o controlador avisa a tela que ela deve preencher o elemento de listagem com a lista de objetos passada por parâmetro. Por final o controlador avisa a tela que ela deve assumir o estado de listagem, ou seja, campos de entrada, botão de salvar e remover desabilitados, deixando apenas o botão novo habilitado. Assim para toda interação que há entre o usuário e a tela, o controlador toma uma decisão.
Espero que tenham entendido como fica a comunicação entre as camadas e tenham visto como a lógica fica divida entre os objetos. Tendo essas informações, creio que fica fácil a compreensão de como a aplicação está estruturada. Abaixo está disponível o código da aplicação e junto um banco de dados embarcado.
Até a próxima.
