{tecnologia, conceitos, negócios, idéias, práticas, .NET, ruby, osx, ios e algo mais}
01/10/2010
Pois é, algumas coisas incomodam a vida de um desenvolvedor. Dentre elas podemos destacar XMLs de configuração.Não sei exatamente a razão de não gostarmos muito deles, mas fato é que quase ninguém gosta. Como alguns de vocês devem saber o NHibernate é uma das ferramentas mais poderosas no que se diz respeito a ORM na plataforma .NET.
Além de podermos configurá-lo utilizando os cruéis costumeiros arquivos XML, existe uma forma de fazer isso via código, com uma sintaxe mais próxima da que costumamos trabalhar diariamente: Fluent NHibernate.
Este não é um post que vai te ensinar a usar o NHibernate. Este é um post que vai te ensinar, um pouco, a usar as configurações fluentes do NHibernate. A idéia é mostrar como configurar a conexão com a base de dados e um pouco de como mapear suas entidades e associações entre elas de uma forma mais simples e verificável utilizando o Fluent NH.
Dentro da página oficial do Fluent NHibernate temos uma seção de Downloads: Let's go!O download do Fluent NHibernate nos trará uma pasta com uma série de dlls, que são as dlls do NHibernate e as dlls do Fluent NHibernate.
Vamos adicionar as seguintes dlls ao nosso projeto:
Agora precisamos configurar a sessão do NHibernate para se conectar ao nosso banco de dados. É claro, não farei isso usando XML e sim o Fluent NH, como mostra o código abaixo:
1 public static ISession ObterSessao(){
2 var session = Fluently.Configure()
3 .Database(MsSqlConfiguration
4 .MsSql2008
5 .ConnectionString(c => c.FromConnectionStringWithKey("ConexaoBanco")))
6 .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
7 .BuildSessionFactory()
8 .OpenSession();
9 return session;
10 }
O código por si só fica explicado, não é mesmo? Na linha 2 iniciamos nossa configuração. Na linha 3 começamos a configurar o banco de dados, e dizemos que é um banco de dados MS SqlServer. na linha 5.
Na linha 5 informo a connection string que está no app.config/web.config e o nome é "ConexaoBanco". Na linha 6 informamos onde estão nossos mapeamentos (este item está mais explicado abaixo). Neste caso dizemos o seguinte: "Nossos mapeamento estão neste assembly!". Isto fará com que essa nossa configuração procure no assembly sendo executado pelo nosso código de mapeamento de entidades.
Nas linhas 7 e 8 pedimos para que uma sessão seja criada à partir da nossa configuração. Bastante simples não?!
Imaginando que meu sistema faz vendas vou utilizar as seguintes entidades:
1 public class Venda{
2 public virtual int Id { get; set; }
3 public virtual IList<linhavenda> Linhas { get; set; }
4 }
5
6 public class LinhaVenda{
7 public virtual int Id { get; set; }
8 public virtual string Produto { get; set; }
9 public virtual Venda Venda { get; set; }
10 public virtual decimal Preco { get; set; }
11 public virtual int Quantidade { get; set; }
12 }
Bastante simples, nada que precise ser comentado. Agora o mapeamento feito com Fluent NHibernate utiliza uma classe que herda de ClassMap<T>. Para cada classe que queremos mapear, precisamos criar uma classe que herda de ClassMap, veja abaixo o mapeamento para nossas 3 entidades:
1 public class VendaMap : ClassMap<Venda>{
2 public VendaMap() {
3 Id(v => v.Id);
4 HasMany(v => v.Linhas).Cascade.All();
5 }
6 }
7
8 public class LinhaVendaMap : ClassMap<LinhaVenda>{
9 public LinhaVendaMap() {
10 Id(l => l.Id);
11 References(l => l.Venda);
12 Map(l => l.Produto);
13 Map(l => l.Preco);
14 Map(l => l.Quantidade);
15 }
16 }
O código de mapeamento fluente praticamente nos diz exatamente o que ele faz, mas vamos ajudar um pouco.
Dentro do construtor de cada classe, colocamos o código de mapeamento. Na linha 3 podemos ver que definimos que o id da nossa entidade vendas no banco deve ser mapeado para a propriedade Id do objeto Venda. Na linha 4 dizemos que nossa Venda possui uma relação "One to Many" com LinhaVenda. Ou seja, uma venda possui muitas linhas de venda. Cascade All diz respeito a "cascatear" os eventos nas entidades da coleção, algo como quando salvar a Venda também salvar as linhas de venda.
No mapeamento da linha de venda temos algumas coisas a notar também. O mapeamento do id é igual ao da classe Venda. Na linha 11 podemos notar que mapeamento a propriedade Venda utilizando o método References. Isso cria uma relação do tipo "Many to One", ou seja, muitas linhas de venda para uma Venda. Isso é o que permitirá que o id de uma venda esteja presente em cada tupla da linha de venda no banco de dados.
Depois nas linhas 12, 13 e 14 mapeamos as propriedades simples utilizando o método Map, que faz com que cada propriedade seja mapeada para uma coluna na tabela respectiva.
Feito isso podemos executar nosso programa e brincar um pouco. Eu utilizei o seguinte código abaixo para criar uma venda com 3 linhas de venda:
1 static void Main(string[] args){
2 var session = SessaoNHibernate.ObterSessao();
3 var venda = new Venda();
4 venda.Linhas = new List<linhavenda>();
5
6 var linha = new LinhaVenda();
7 linha.Preco = 102;
8 linha.Quantidade = 4;
9 linha.Produto = "Prod 1";
10 linha.Venda = venda;
11 venda.Linhas.Add(linha);
12
13 var linha2 = new LinhaVenda();
14 linha2.Preco = 1;
15 linha2.Quantidade = 5;
16 linha2.Produto = "prod 2!";
17 linha2.Venda = venda;
18 venda.Linhas.Add(linha2);
19
20 var linha3 = new LinhaVenda();
21 linha3.Preco = 333;
22 linha3.Quantidade = 1;
23 linha3.Produto = "prod 3";
24 linha3.Venda = venda;
25 venda.Linhas.Add(linha3);
26
27 session.SaveOrUpdate(venda);
28 session.Close();
29 }
Esse código criará uma Venda, e suas respectivas LinhaVenda, fará a inserção desses dados no banco, de forma bastante transparente.
Se você quiser que seus mapeamentos sejam transformados em script para o banco de dados e já executado contra o database, altere o código da listagem de configuração para este código abaixo:
1 public static ISession ObterSessao(){
2 var session = Fluently.Configure()
3 .Database(MsSqlConfiguration
4 .MsSql2008
5 .ConnectionString(c => c.FromConnectionStringWithKey("conexaopadrao")))
6 .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
7 .ExposeConfiguration(cfg => new SchemaExport(cfg)
8 .Create(true, true))
9 .BuildSessionFactory()
10 .OpenSession();
11 return session;
12 }
Desta forma o código das linhas 7 e 8 farão com que o script do banco seja gerado e executado.Não preciso mencionar que esse código NÃO deve ir para produção não é mesmo?!
Bom galera, é basicamente isso. O NHibernate é muito mais poderoso e possui uma série de recursos, bem como o Fluent NHibernate também. A idéia deste post era fornecer, de uma maneira simples e direta, um guia de como começar a trabalhar com o Fluent.Qualquer dúvida ou sugestão, basta entrar em contato.Espero que aproveitem.
Att,
Vinicius Quaiato.