Blog «EM1£1Ø»2HÐ

Porque compartilhar conhecimento é evoluir!

Olá caros leitores! Depois de muito tempo(devido a correria) estou postando a segunda parte do “Criando uma pequena aplicacao usando nhibernate”.

Ver Parte 1

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.

Download

Faça Pequena Aplicação com NHibernate (VS2008)

Categorias: Tutoriais Tags: , , ,

Leave a Reply