No .Net Architects Day eu apresentei rapidamente um exemplo iniciante de um sistema de blog durante minha palestra de DDD. Eu havia criado algumas entidades, post e comentário, e tudo funcionava.

Aí resolvi criar outra entidade: usuário. Criei a entidade, criei o controlador as views, liguei tudo, e tudo continuava funcionando. Não criei repositórios específicos, nem mapeamento, nem nada a mais, só a entidade e as partes de interface gráfica. Estava usando NHibernate para resolver o "problema" da relação objeto e dados relacionais. De repente a tabela apareceu lá, os dados salvavam corretamente, o SQL gerado era otimizado e eu estava feliz.

Tudo funcionava. Tudo automático. Muitos me perguntaram como isso foi feito. A resposta é muito simples. Além do NHibernate usei também um pouco de NHibernate Fluente e sua possibilidade de trabalhar automapeamento baseado em convenções. Minha classe de configuração do NHibernate fazia mapeamento de três formas: a básica do NH (com XML), a fluente (do NH fluente), e a automática. O código da classe de autoconfiguração é muito curto, cerca de 60 linhas:

public class Autoconfiguracao
{
    private static ISessionFactory _factory;
    public static ISessionFactory Configurar(bool gerarBanco = true)
    {
        if (_factory != null)
            return _factory;

        var config = Fluently.Configure()
            .Database(
            FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005
            .ConnectionString(c =>
              c.Is(@"Data Source=.\sqlexpress;Initial Catalog=DNAD09Blog;Integrated Security=True"))
              .ShowSql()
        );

        config.Mappings(m =>
        {
            m.HbmMappings.AddFromAssemblyOf<Autoconfiguracao>();

            m.FluentMappings
                .AddFromAssemblyOf<Autoconfiguracao>();

            m.AutoMappings.Add(
                AutoPersistenceModel.MapEntitiesFromAssemblyOf<Postagem>()
                .WithSetup(s => s.IsBaseType = (type => type == typeof(EntidadeComId)))
                .ConventionDiscovery.Setup(c =>
                {
                    c.Add(PrimaryKey.Name.Is(x => x.EntityType.Name + "_Id"));
                    c.Add(DefaultLazy.AlwaysFalse());
                    //c.Add(ForeignKey.Format((prop, tipo) => prop.Name + "_Id"));
                    c.Add(Table.Is(x => x.EntityType.Name));
                }
                )
                .Where(t =>
                    t.Namespace == "Dnad09.Blog.Dominio.Entidades"
                    && t.IsInterface == false
                    && t.IsAbstract == false
                )
            );
        }
        );

        if (gerarBanco)
        {
            config.ExposeConfiguration(cfg =>
            {
                var schemaExport = new SchemaExport(cfg);
                schemaExport.Create(false, true);
            });
        }
        _factory = config.BuildSessionFactory();
        return _factory;
    }
}

 

Na parte de configuração, que vai até "config.Mappings" (linhas 17 a 42) todas as chamadas são baseadas em Lambdas. Em seguida se o flag gerar bancos é configurado então o banco é criado, e a factory do NH é retornada. Nela estão todas as configurações do NH, e a criação de sessões do NH, que é o que realmente importa, é muito facilitada. Para trocar o banco de dados para Oracle, por exemplo, bastaria trocar a chamada "Fluently.Configure" (linhas 9 a 15) para trabalhar com este banco de dados.

O mais interessante é a possibilidade de mapear automaticamente apenas a parte que interessa. Podemos mapear algumas classes automaticamente, aceitando as convenções, e em outras utilizar mapeamento fluente ou baseado em XML. Em um cliente recentemente fizemos isso através de atributos: se uma classe tinha um atributo de automapeamento que criamos, então usávamos ela no automapeamento. Senão, teríamos que trabalhar o mapeamento de forma fluente ou com XML.

A produtividade neste tipo de cenário é gigantesca. O foco é o domínio, ou seja, o coração de um software de negócios. A persistência dos dados não é sequer uma preocupação.

Essa abordagem toda é muito legal, mas levantou questões interessantes no .Net Architects Day, que foram inclusive discutidas em outras palestras, como a dada pelo Juliano, que foi mais focada em ORM. Entre elas, a mais polêmica foi sem dúvida a seguinte:

– O DBA morreu?

Minha resposta desta pergunta nesta quarta-feira de manhã. Aguardem.

Giovanni Bassi

Arquiteto e desenvolvedor, agilista, escalador, provocador. É fundador e CSA da Lambda3. Programa porque gosta. Acredita que pessoas autogerenciadas funcionam melhor e por acreditar que heterarquia é mais eficiente que hierarquia. Foi reconhecido Microsoft MVP há mais de dez anos, dos mais de vinte que atua no mercado. Já palestrou sobre .NET, Rust, microsserviços, JavaScript, TypeScript, Ruby, Node.js, Frontend e Backend, Agile, etc, no Brasil, e no exterior. Liderou grupos de usuários em assuntos como arquitetura de software, Docker, e .NET.