Quem me conhece sabe como sou fã no NHibernate, já utilizo há vários anos e já se comprovou como um ORM completo e confiável. Se você não conhece dê uma lida nestes sites para conhecer:

  1. http://nhibernate.info
  2. https://github.com/nhibernate

Mas mesmo gostando do NHibernate ele tinha se tornado um problema desde o lançamento do .NET Core, na verdade ele não era o problema mas sim a falta dele no ecossistema do .NET Core, a Microsoft lançou em conjunto com o .NET Core o Entity Framework Core, mas como pode ser visto no roadmap do EF ele ainda tem algumas features faltando para ser considerado um ORM completo.

A esperança era que em algum momento o NHibernate fosse portado para o .NET Core, a esperança era pequena porque a dependência por APIs do .NET Framework (full framework) era grande. Nesse vácuo outros frameworks começaram a se despontar como o Dapper, mas não dá para comparar as features que tinhamos no NHibernate com um micro ORM.

Quando a Microsoft anunciou o .NET Standard 2.0 as esperanças renasceram, a proposta de incorporar uma boa parte das APIs do .NET Framework no .NET Core era muito animadora, até gravamos um podcast sobre isso.

A partir desse anuncio fiquei monitorando o repositório do NHibernate Core para ver como estava o andamento do trabalho, até surgir a branch NH999 que está ligado ao porte do NH para o .NET Core 2, fiquei animado e monitorando os PRs do NH até ver que em agosto o Nathan Brown fez um PR no qual ele fala que os testes já estão passando no Windows com SQL Server e ele já estava disponibilizando os nugets em um feed público.

Na mesma semana fui testar e estava funcionando, vou mostrar para vocês como vocês podem reproduzir esse teste, porque se vocês forem como eu só vão acreditar vendo.

Mão na massa

Primeira coisa é necessário configurar no Visual Studio um novo Feed de Nuget, adicione a url https://ci.appveyor.com/nuget/nhibernate-core-6cm11v2xdhud como um source de nuget.

Adicione o pacote NHibernate.Driver.SqlServer, não se esqueça de pesquisar no feed que você acabou de adicionar, é ncessário marcar a opção pré-release.

Depois de instalado vamos criar a configuração do NHibernate a moda antiga, com os benditos XML (eu costumo fazer mapeamento com o Fluent NHibernate, mas ele ainda não está portado). Para o nosso teste essa configuração será suficiente, primeiro vamos configurar a conexão com um arquivo hibernate.cfg.xml, esse arquivo deve estar na raiz do projeto e deve ser configurado nas propriedades do arquivo do projeto que o Build Action para None e Copy do output Directory para Copy Aways, o conteúdo do arquivo será o seguinte:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
      <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
  </configSections>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
	<session-factory>
	  <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
	  <property name="connection.connection_string">Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=NHTeste;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False</property>
	  <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
	  <mapping assembly="ConsoleApp1"/>
	</session-factory>
  </hibernate-configuration>
</configuration>

Vamos mapear uma entidade simples para inserir e logo depois ler os dados. A entidade e a tabela estão logo abaixo:

    public class City
    {
        public virtual int Id { get;  set; }
        public virtual long Population { get; set; }
        public virtual string Name { get; set; }
    }
CREATE TABLE [dbo].[City] (
    [Id]         INT           IDENTITY (1, 1) NOT NULL,
    [Name]       VARCHAR (255) NULL,
    [Population] BIGINT        NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

O arquivo de mapeamento tem o nome de Mapping.hbm.xml esse arquivo deve estar na raiz do projeto e deve ser configurado nas propriedades do arquivo do projeto que o Build Action para Embeded Resource e Copy do output Directory para Do not copy, o conteúdo do arquivo será o seguinte:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="ConsoleApp1" namespace="ConsoleApp1" auto-import="true">
  <class name="City">
    <id name="Id" type="int" generator="identity"/>
    <property name="Name" />
    <property name="Population" />
  </class>
</hibernate-mapping>

Chegando nesse ponto basta fazer a conexão para obter a sessão do NHibernate, fiz tudo em um console application bem simples só para demonstrar que ele insere e consegue selecionar valores.

class Program
{
    static void Main(string[] args)
    {
        
        
        var configuration = new Configuration();
        configuration.Configure();
        var SessionFactory = configuration.BuildSessionFactory();
        var session = SessionFactory.OpenSession();

        Console.Write("Digite o nome da Cidade =");
        var name = Console.ReadLine();

        Console.Write("Digite a populaçao=");
        var population = Console.ReadLine();


        var city = new City { Name = name, Population = Convert.ToInt16(population) };
        session.SaveOrUpdate(city);
        session.Flush();

        var cities = session.Query<City>()
            .Where(p => p.Population > 1000)
            .ToList();

        Console.WriteLine($"Cidades com mais de 1000 pessoas:");
        cities.ForEach(x =>
        {
            Console.WriteLine($"{x.Name} -> {x.Population}");
        });
        Console.ReadLine();
        session.Close();

    }
}

Quando você executar o programa ele irá pedir um nome da cidade depois da população inserir e exibir as cidade que tem mais de 1000.

Como eu disse o teste é bem simples, mas já dá para ver que o trabalho está seguindo e que logo teremos tudo funcionando.

Isso tudo só foi possível por causa de 2 fatores:

  1. .NET Standard 2 está cobrindo muito mais APIs que o .NET Framewok já cobria. Com isso ficou muito mais fácil para a equipe do NHibernate portar para o .NET Core 2.0.
  2. Disponibilidade do Nathan Brown para portar, Thanks Nathan!

O código desse post pode ser visto aqui.

Recomendo dar uma lida na thread desse Pull Request no GitHub

Vamos torcer para sair logo! E aí o que acharam da novidade?

Victor Cavalcante

Victor Cavalcante é marido da Mariana Frioli, pai do Eduardo, Microsoft MVP, trabalha com desenvolvimento web a 11 anos e é focado em padrões de desenvolvimento para web. Trabalha na Lambda3 (www.lambda3.com.br), empresa ágil que insiste em fazer software certo. É ainda professor universitário e atua no grupo .NET Architects desde seu início. Acompanhe seu twitter para saber as novidades:@vcavalcante.