{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
2
3
4
5
6
7
8
9
10
public static ISession ObterSessao(){
var session = Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2008
.ConnectionString(c => c.FromConnectionStringWithKey("ConexaoBanco")))
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.BuildSessionFactory()
.OpenSession();
return session;
}
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
2
3
4
5
6
7
8
9
10
11
12
public class Venda {
public virtual int Id { get; set; }
public virtual IList<LinhaVenda> Linhas { get; set; }
}
public class LinhaVenda {
public virtual int Id { get; set; }
public virtual string Produto { get; set; }
public virtual Venda Venda { get; set; }
public virtual decimal Preco { get; set; }
public virtual int Quantidade { get; set; }
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class VendaMap : ClassMap<Venda> {
public VendaMap() {
Id(v => v.Id);
HasMany(v => v.Linhas).Cascade.All();
}
}
public class LinhaVendaMap : ClassMap<LinhaVenda> {
public LinhaVendaMap() {
Id(l => l.Id);
References(l => l.Venda);
Map(l => l.Produto);
Map(l => l.Preco);
Map(l => l.Quantidade);
}
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static void Main(string[] args) {
var session = SessaoNHibernate.ObterSessao();
var venda = new Venda();
venda.Linhas = new List<LinhaVenda>();
var linha = new LinhaVenda();
linha.Preco = 102;
linha.Quantidade = 4;
linha.Produto = "Prod 1";
linha.Venda = venda;
venda.Linhas.Add(linha);
var linha2 = new LinhaVenda();
linha2.Preco = 1;
linha2.Quantidade = 5;
linha2.Produto = "prod 2!";
linha2.Venda = venda;
venda.Linhas.Add(linha2);
var linha3 = new LinhaVenda();
linha3.Preco = 333;
linha3.Quantidade = 1;
linha3.Produto = "prod 3";
linha3.Venda = venda;
venda.Linhas.Add(linha3);
session.SaveOrUpdate(venda);
session.Close();
}
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
2
3
4
5
6
7
8
9
10
11
12
public static ISession ObterSessao(){
var session = Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2008
.ConnectionString(c => c.FromConnectionStringWithKey("conexaopadrao")))
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaExport(cfg)
.Create(true, true))
.BuildSessionFactory()
.OpenSession();
return session;
}
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.