NHibernate - Guia Rápido

Neste capítulo, discutiremos sobre o que é o NHibernate, em quais plataformas ele pode ser implementado, quais são suas vantagens e outros aspectos relacionados a ele.

O que é NHibernate?

NHibernate é um mapeador objeto-relacional de software livre maduro para a estrutura .NET. É ativamente desenvolvido, totalmente caracterizado e usado em milhares de projetos de sucesso. É construído em cima deADO.NET e a versão atual é NHibernate 4.0.4.

  • NHibernate é um mapeador objeto-relacional de código aberto .NET e é distribuído sob o GNU Lesser General Public License.

  • Ele é baseado no Hibernate, que é um mapeador relacional de objetos Java popular e possui uma base de código muito madura e ativa.

  • Ele fornece uma estrutura para mapear um modelo de domínio orientado a objetos para um banco de dados relacional tradicional.

  • NHibernate foi iniciado por Tom Barrett e esse projeto existe desde fevereiro de 2003, quando foi o primeiro commit.

  • É um grande projeto e oferece muitas funcionalidades.

  • Existe um NuGet package disponível, o que torna muito fácil adicionar a um projeto.

Por que NHibernate?

Agora a questão é por que precisamos object-relational mappers? É porque há uma desconexão entre o mundo do objeto e o mundo relacional.

  • No mundo do objeto, tudo se baseia em objects; chamamos de objetos aquelas coisas que contêm nossos dados.

  • O mundo relacional é todo baseado em conjuntos e estamos lidando com tabelas e linhas que são diferentes do mundo do objeto.

  • No mundo do objeto, temos unidirectional associations. Se um cliente tem um ponteiro para um pedido, isso não significa necessariamente que um pedido tem um ponteiro de volta para um cliente, pode ou não.

  • No mundo relacional, todas as associações são bidirectional e isso pode ser feito por uma chave estrangeira.

  • Todas as associações são inerentemente bidirecionais, portanto, quando estamos lidando com mapeamento objeto-relacional, também precisamos lidar com essa desconexão.

  • No mundo dos objetos, estamos trabalhando com ponteiros que são unidirecionais, enquanto no mundo relacional, temos chaves estrangeiras que são inerentemente bidirecionais.

  • O mundo do objeto tem essa noção de herança, onde um veículo pode ter várias subclasses diferentes, então um carro é um tipo de veículo, um barco é um tipo de veículo e um carro esporte é um tipo de carro, esses tipos de relações de herança.

  • O mundo relacional não tem essa noção de herança.

Mapeamento

Então, como mapeamos todos esses disjoint relationships?Este conceito de mapeamento vem do mapeador relacional de objetos. Existem basicamente três coisas para entender, conforme mostrado no diagrama a seguir.

  • Em seu aplicativo, você precisará de definições de classe, que normalmente é o código C # e seu código .NET que representa nossas classes, como classe Employee, classe Customer, classe Order, etc.

  • Na parte inferior, você pode ver um esquema de banco de dados, que é o nosso Data Definition Language em um banco de dados relacional que especifica a aparência de uma tabela de clientes, a aparência de uma tabela de funcionários.

  • Entre eles, temos os metadados de mapeamento que informam ao mapeador relacional de objetos como traduzir do mundo do objeto em C # para o mundo do banco de dados em termos de linhas e colunas e relacionamentos de chave estrangeira.

  • Esses metadados de mapeamento podem ser representados em uma variedade de maneiras diferentes e veremos várias dessas maneiras diferentes, mais comuns no aplicativo NHibernate.

  • É representado por HBM (Hibernate Mapping) arquivos, que são arquivos XML.

Suporte de banco de dados

NHibernate oferece suporte a uma ampla variedade de bancos de dados diferentes. Qualquer banco de dados relacional existente pode ser acessado no NHibernate.

  • O servidor SQL é o principal banco de dados suportado, é o que a maioria dos desenvolvedores está usando durante o desenvolvimento, provavelmente é o mais comum.

  • Isso também works very well with Oracle.

  • Também suporta DB2, Firebird, MySQL, PostgreSQL, SQL Lite

  • Também tem ODBC and OLEDB drivers.

Hoje em dia, muitos sistemas são projetados com arquitetura em camadas, o NHibernate também tem e funciona perfeitamente bem com esse design.

Arquitetura em camadas

Uma arquitetura em camadas divide um sistema em vários grupos, onde cada grupo contém o código que trata de uma área de problema específica e esses grupos são chamados de camadas. A maioria dos aplicativos de nível empresarial usahigh-level application architecture que consistem em três camadas -

  • A camada de apresentação
  • A camada de negócios
  • A camada de persistência

Por exemplo, uma camada de interface do usuário, também conhecida como camada de apresentação, pode conter todo o código do aplicativo para construir páginas da web e processar a entrada do usuário.

Um grande benefício da abordagem de camadas é que muitas vezes você pode fazer alterações em uma camada sem qualquer interrupção significativa nas outras camadas, tornando os sistemas lesser fragile and more maintainable.

Camada de apresentação

  • É a camada superior, que contém o código responsável por desenhar a interface do usuário, páginas, diálogos ou telas, coletar a entrada do usuário e controlar a navegação.

Camada de Negócios

  • A camada de negócios é responsável por implementar quaisquer regras de negócios ou requisitos de sistema que os usuários entendam como parte do domínio do problema.

  • Também reutiliza o modelo definido pela camada de persistência.

Camada de Persistência

  • A camada de persistência consiste em classes e componentes responsáveis ​​por salvar e recuperar os dados do aplicativo.

  • Essa camada também define um mapeamento entre a classe do modelo e o banco de dados. NHibernate é usado principalmente nesta camada.

Base de dados

  • O banco de dados existe fora do aplicativo .NET.
  • É a representação real e persistente do estado do sistema.
  • Se um banco de dados SQL for usado, o banco de dados incluirá o esquema relacional e possivelmente os procedimentos armazenados.

Aulas de ajudantes / utilitários

  • Cada aplicativo tem um conjunto de classes auxiliares ou utilitárias que suportam as outras camadas: por exemplo, widgets de IU, classes de mensagens, classes de exceção e utilitários de registro.

  • Esses elementos não são considerados camadas, pois não obedecem às regras de dependência entre camadas em uma arquitetura em camadas.

Arquitetura NHibernate

  • É uma visão de alto nível do aplicativo NHibernate e você também pode ver a arquitetura NHibernate simples.

  • O código do aplicativo usa o NHibernate ISession e IQuery APIs para operações de persistência e só precisa gerenciar transações de banco de dados, de preferência usando o NHibernate ITransaction API.

Antes de realmente começarmos a usar o NHibernate, precisamos entender a base sobre a qual ele foi construído. NHibernate é uma tecnologia de persistência baseada na ideia de mapeamento relacional de objetos ou ORM.

O que é ORM?

Mapeamento Objeto-Relacional (ORM) é um programming techniquepara converter dados entre sistemas de tipos incompatíveis em linguagens de programação orientadas a objetos. Em outras palavras, é o conceito de mapear os objetos de negócios de um aplicativo para tabelas de banco de dados relacionais, de modo que os dados possam ser facilmente acessados ​​e atualizados inteiramente por meio do modelo de objeto de um aplicativo.

  • Como você já sabe, os bancos de dados relacionais fornecem um bom meio de armazenar dados, enquanto a programação orientada a objetos é uma boa abordagem para construir aplicativos complexos.

  • NHibernate e ORM em geral são mais relevantes para aplicativos com lógica de negócios não trivial, o modelo de domínio e algum tipo de banco de dados.

  • Com ORM, é muito fácil criar uma camada de tradução que pode facilmente transformar objetos em dados relacionais e vice-versa.

  • O acrônimo ORM também pode significar modelagem de função de objeto, e este termo foi inventado antes que o mapeamento objeto / relacional se tornasse relevante.

  • Ele descreve um método para análise de informações, usado na modelagem de banco de dados.

Por que ORM?

ORM é um framework que permite mapear o mundo dos objetos encontrados em linguagens orientadas a objetos para linhas em tabelas relacionais encontradas em bancos de dados relacionais

Para entender esse conceito, vamos dar uma olhada no diagrama a seguir.

  • No diagrama acima, você pode ver que temos uma tabela chamada Funcionário no lado direito que contém colunas com cada dado associado a um funcionário individual.

  • Temos uma coluna para um Id que identifica exclusivamente cada funcionário.

  • Uma coluna para o nome do funcionário, outra coluna para a data de ingresso e, finalmente, uma coluna com a idade do funcionário.

  • Se quiséssemos escrever algum código para armazenar um novo funcionário nas tabelas, não é tão fácil.

  • No diagrama acima, você também pode ver que temos um objeto funcionário que possui campos para Id, nome, data de adesão e idade.

  • Sem um ORM, temos que traduzir esse objeto em algumas instruções SQL diferentes que irão inserir os dados do funcionário na tabela de funcionários.

  • Portanto, escrever código para criar o SQL para fazer o cenário acima não é tão difícil, mas é um pouco tedioso e muito fácil errar.

  • Usando um ORM como o NHibernate, podemos declarar como certas classes devem ser mapeadas para tabelas relacionais e deixar o ORM ou NHibernate lidar com o trabalho desagradável de criar o SQL para inserir, atualizar, excluir, em dados de consulta em nossa tabela de funcionários.

  • Isso nos permite manter nosso código focado no uso de objetos e ter esses objetos convertidos automaticamente em tabelas relacionais.

  • Então, o que realmente faz um ORM é nos poupar de ter que mapear objetos manualmente para tabelas.

Para começar a trabalhar no NHibernate, precisaremos do Visual Studio e do pacote NHibernate.

Instalação do Visual Studio

A Microsoft fornece um free version do Visual Studio, que também contém SQL Server e pode ser baixado de https://www.visualstudio.com A seguir estão as etapas para a instalação.

Step 1 - Assim que o download for concluído, execute o instalador e a seguinte caixa de diálogo será exibida.

Step 2 - Clique no botão Instalar e iniciará o processo de instalação.

Step 3 - Assim que o processo de instalação for concluído com êxito, você verá a seguinte caixa de diálogo.

Step 4 - Feche esta caixa de diálogo e reinicie o computador, se necessário.

Step 5- Agora abra o Visual Studio no menu Iniciar, que abrirá a seguinte caixa de diálogo. A preparação levará algum tempo pela primeira vez.

Step 6 - Depois de fazer tudo isso, você verá a janela principal do Visual Studio.

Instalação do pacote NHibernate

NHibernate é um mapeador objeto-relacional de software livre maduro para a estrutura .NET. Ele é desenvolvido ativamente, totalmente caracterizado e usado em milhares de projetos de sucesso. Você pode instalar o pacote NHibernate com os seguintes métodos.

Download direto

  • Baixe o zip do arquivo de https://sourceforge.net/ que contém todos os binários necessários.

  • Extraia este arquivo zip e inclua todos esses binários em seu projeto.

Instalar usando NuGet

  • Outra maneira de instalar o NHibernate é usar o NuGet para instalar o pacote NHibernate, que é de longe a maneira mais fácil de incorporar o NHibernate em um projeto.

  • Ele vai baixar todas as dependências do NHibernate e criar referências para todos os assemblies necessários.

  • Para instalar o NHibernate, execute o seguinte comando no console do gerenciador de pacotes.

install-package NHibernate

Agora você está pronto para iniciar seu aplicativo.

Neste capítulo, veremos como iniciar um exemplo simples usando NHibernate. Estaremos construindo umsimple console application. Para criar um aplicativo de console, usaremos o Visual Studio 2015, que contém todos os recursos que você precisa para criar, testar seu aplicativo usando o pacote NHibernate.

A seguir estão as etapas para criar um projeto usando os modelos de projeto disponíveis no Visual Studio.

Step 1 - Abra o Visual Studio e clique na opção de menu Arquivo → Novo → Projeto.

Step 2 - Uma nova caixa de diálogo Projeto é aberta.

Step 3 - No painel esquerdo, selecione Modelos → Visual C # → Windows.

Step 4 - No painel do meio, selecione Aplicativo de console.

Step 5 - Digite o nome do projeto, 'NHibernateDemoApp', no campo Nome e clique em Ok para continuar.

Step 6 - Depois que o projeto for criado pelo Visual Studio, você verá vários arquivos exibidos na janela do Solution Explorer.

Como você sabe que criamos um projeto de aplicativo de console simples, agora precisamos incluir o pacote NHibernate em nosso projeto de console.

Vá para o menu Ferramentas e selecione Gerenciador de pacotes NuGet → Console do gerenciador de pacotes para abrir a janela Console do gerenciador de pacotes.

Especifique o comando mostrado acima Package Manager Consolejanela e pressione Enter, ele irá baixar todas as dependências do NHibernate e criar referências para todos os assemblies necessários. Assim que a instalação for concluída, você verá a mensagem conforme mostrado na imagem a seguir.

Agora que temos o NHibernate adicionado, podemos iniciar a implementação. Então, vamos começar mapeando um muito simplestable chamado Student, que simplesmente tem uma chave primária inteira chamada ID e uma coluna FirstName e LastName.

Precisamos de uma classe para representar este aluno, então vamos criar uma nova classe chamada Aluno clicando com o botão direito do mouse no projeto no explorador de soluções e então selecione Adicionar → Classe que abrirá a caixa de diálogo Adicionar Novo Item.

Entrar Student.csno campo do nome, clique no botão Adicionar. Nesta classe de aluno, precisamos ter nossa chave primária inteira chamada ID, e precisamos criar esta string,FirstName e LastName campos conforme mostrado na seguinte implementação completa da classe Aluno.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 
   
   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstMidName { get; set; } 
   } 
}

Ao lidar com modelos no aplicativo NHibernate, é mais fácil tornar todos os seus campos virtuais. Portanto, este é o nosso modelo NHibernate simples que usaremos e mapearemos para o banco de dados de back end.

Agora vamos para o método Main na classe Program e criar um novo objeto de configuração NHibernate.

A primeira coisa que precisamos fornecer é o connection string. Esta é uma string de conexão específica do banco de dados e a maneira mais fácil de encontrar a string de conexão é clicando com o botão direito do mouse no banco de dados emSQL Server Object Explorer e selecione Propriedades.

Isso abrirá a janela Propriedades, agora role para baixo e você verá o campo String de conexão na janela Propriedades.

Copie a string de conexão e especifique em seu código. A seguir está a implementação do método Main no qual precisamos configurar o NHibernate.

using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;

using System;
using System.Linq;
using System.Reflection;

namespace NHibernateDemoApp {

   class Program {
   
      static void Main(string[] args) {
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
         
                     
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>();
         });
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly());
         
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()) {
         
            using (var tx = session.BeginTransaction()) {
               //perform database logic 
               tx.Commit();
            }
            
            Console.ReadLine(); 
         } 
      } 
   } 
}

Após a string de conexão, precisamos fornecer um driver, que é o SQLClientDriver e também precisamos fornecer um dialeto, qual versão do SQL Server, e usaremos o MS SQL 2008.

NHibernate agora sabe como se conectar ao banco de dados. A outra coisa que precisamos fazer é fornecer uma lista de modelos que iremos mapear.

Podemos fazer isso adicionando uma montagem, portanto, especificando o Assembly.GetExecutingAssemblye é aqui que o programa encontrará os arquivos de mapeamento. Arquivos de mapeamento dizem ao NHibernate como ir das classes C # para as tabelas do banco de dados.

SessionFactory compila todos os metadados necessários para inicializar o NHibernate. SessionFactory pode ser usada para construir sessões, que são aproximadamente análogas às conexões de banco de dados. Portanto, a maneira adequada é usá-lo no bloco de uso. eu posso dizervar session é igual a sessionFactory.OpenSession e vou querer fazer isso dentro de sua transação.

Assim que a sessão for aberta, podemos dizer à sessão para iniciar uma nova transação e, então, executar alguma lógica aqui. Portanto, execute alguma lógica de banco de dados e, finalmente, confirme essa transação.

Neste capítulo, iremos abordar alguns basic mappinge você sabe que, desde o capítulo anterior, temos a tabela do banco de dados, bem como a definição da classe C #. Agora precisamos de um mapeamento que explica como traduzir do C # para o banco de dados e vice-versa.

Então, vamos adicionar um novo arquivo XML clicando com o botão direito do mouse no projeto no gerenciador de soluções e selecione Adicionar → Novo item ...

Entrar Student.hbm.xmlno campo de nome. Precisamos especificar uma montagem padrão que seráNHibernateDemoAppe também especificar um namespace padrão. Isso apenas reduz muitas das outras definições de tipo que faremos neste arquivo.

A seguir está a implementação no arquivo XML -

<?xml version = "1.0" encoding = "utf-8" ?> 

<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">

   <class name = "Student"> 
      <id name = "ID">
        <generator class = "native"/> 
      </id> 
		
      <property name = "LastName"/> 
      <property name = "FirstMidName"/> 
   </class> 
   
</hibernate-mapping>

A próxima coisa que precisamos é definir uma classe; esta aula vai ser nossaStudent class. Em seguida, precisamos dizer ao NHibernate o nome do id, que é ID e eu também tenho que dizer ao NHibernate como gerar IDs, então nosso gerador será do tipo nativo.

O gerador de tipo nativo significa que em um banco de dados como o SQL Server, ele usará a coluna de identidade, o tipo de identidade.

A próxima coisa que devemos fazer é fornecer os nomes das propriedades. Portanto, adicione mais duas propriedades para FirstName e LastName.

Agora, estamos lendo esses arquivos de mapeamento da montagem. Portanto, a maneira preferida de fazer isso é ter essesHBM filesincorporado em sua montagem. Podemos fazer isso simplesmente definindo uma propriedade.

Agora, clique com o botão direito do mouse no projeto no explorador de soluções e selecione Propriedades, você verá o Build Action field em que o Conteúdo é selecionado por padrão.

Selecione o recurso incorporado na lista suspensa.

Portanto, isso realmente incorpora esse arquivo XML dentro do NHibernateDemoApp montagem.

Neste capítulo, vamos cobrir o básico CRUD operations. Agora que nosso sistema está pronto para iniciar, já que implementamos com sucesso nossa classe de domínio Student, também definimos os arquivos de mapeamento e configuramos o NHibernate. Agora podemos usar algumas consultas para realizar operações CRUD.

Criar Dados

Como você pode ver, não temos dados em nossa tabela de alunos em NHibernateDemoDB base de dados.

Portanto, para adicionar alguns dados, precisamos realizar o Add/Create operação conforme mostrado abaixo.

using (var session = sefact.OpenSession()) { 

   using (var tx = session.BeginTransaction()) { 
     
      var student1 = new Student { 
         ID = 1, 
         FirstMidName = "Allan", 
         LastName = "Bommer" 
      }; 
      
      var student2 = new Student { 
         ID = 2, 
         FirstMidName = "Jerry", 
         LastName = "Lewis" 
      }; 
      
      session.Save(student1); 
      session.Save(student2); 
      tx.Commit(); 
   } 
   
   Console.ReadLine(); 
}

Como você pode ver, criamos dois alunos e chamamos o método Save () do OpenSession e, em seguida, chame o Commit () do BeginTransaction. Aqui está a implementação completa emProgram.cs Arquivo

using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 
   
   class Program { 
      
      static void Main(string[] args) { 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 

            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
         }); 
   
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
               
               var student1 = new Student { 
                  ID = 1,  
                  FirstMidName = "Allan", 
                  LastName = "Bommer" 
               }; 

               var student2 = new Student { 
                  ID = 2, 
                  FirstMidName = "Jerry", 
                  LastName = "Lewis" 
               }; 
            
               session.Save(student1); 
               session.Save(student2); 
               tx.Commit();
            } 
            
            Console.ReadLine(); 
         } 
      } 
   } 
}

Agora vamos executar este aplicativo e ir para o SQL Server Object Explorer e atualizar seu banco de dados. Você verá que os dois alunos acima agora são adicionados à tabela Student no banco de dados NHibernateDemoDB.

Leia os dados da tabela do aluno

Você pode ver que agora temos dois registros em nossa tabela de alunos. Para ler esses registros da tabela, precisamos chamar oCreateCriteria() do OpenSession, conforme mostrado no código a seguir.

using (var session = sefact.OpenSession()) { 
   
   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>(); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", 
            student.ID,student.FirstMidName, student.LastName); 
      } 
      
      tx.Commit(); 
   } 
   
   Console.ReadLine(); 
}

Portanto, se você deseja a lista de registro, podemos simplesmente dizer lista do tipo Aluno.

Agora use o foreach por meio de todos os alunos e diga para imprimir a identidade, FirstMidName e LastNameno console. Agora, vamos executar este aplicativo novamente e você verá a seguinte saída na janela do console.

1 Allan Bommer
2 Jerry Lewis

Você também pode recuperar qualquer registro, especificando o ID no Get() método de OpenSession usando o código a seguir.

using (var session = sefact.OpenSession()) { 
   
   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>(); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      }
      
      var stdnt = session.Get<Student>(1); 
      Console.WriteLine("Retrieved by ID"); 
      Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, 
         stdnt.FirstMidName, stdnt.LastName); 
      tx.Commit();
   } 
	
   Console.ReadLine(); 
}

Agora, ao executar seu aplicativo, você verá a seguinte saída.

1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer

Atualizar registro

Para atualizar o registro na tabela, precisamos primeiro buscar esse registro específico e, em seguida, atualizar esse registro chamando o Update() método de OpenSession conforme mostrado no código a seguir.

using (var session = sefact.OpenSession()) { 

   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>(); 
     
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      }
      
      var stdnt = session.Get<Student>(1); 
      Console.WriteLine("Retrieved by ID"); 
      Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
      
      Console.WriteLine("Update the last name of ID = {0}", stdnt.ID); 
      stdnt.LastName = "Donald"; 
      session.Update(stdnt); 
      Console.WriteLine("\nFetch the complete list again\n"); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      } 
      
      tx.Commit();
   } 
   
   Console.ReadLine();
}

Agora, ao executar seu aplicativo, você verá a seguinte saída.

1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Update the last name of ID = 1
Fetch the complete list again
1 Allan Donald
2 Jerry Lewis

Como você pode ver, LastName de ID igual a 1 é atualizado de Bommer para Donald.

Apagar registro

Para excluir qualquer registro da tabela, precisamos primeiro buscar aquele registro específico e, em seguida, excluí-lo chamando o Delete() método de OpenSession conforme mostrado no código a seguir.

using (var session = sefact.OpenSession()) { 
   
   using (var tx = session.BeginTransaction()) { 
      var students = session.CreateCriteria<Student>().List<Student>();
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, 
            student.FirstMidName, student.LastName); 
      }
      
      var stdnt = session.Get<Student>(1); 
      Console.WriteLine("Retrieved by ID"); 
      Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
      
      Console.WriteLine("Delete the record which has ID = {0}", stdnt.ID); 
      session.Delete(stdnt);
      Console.WriteLine("\nFetch the complete list again\n"); 
      
      foreach (var student in students) { 
         Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName, 
            student.LastName); 
      } 
      
      tx.Commit();
   } 
	
   Console.ReadLine(); 
}

Agora, ao executar seu aplicativo, você verá a seguinte saída.

1 Allan Donald
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Delete the record which has ID = 1
Fetch the complete list again
2 Jerry Lewis

Como você pode ver, o registro que possui ID igual a 1 não está mais disponível no banco de dados. Você também pode ver o banco de dados no SQL Server Object Explorer.

Neste capítulo, entenderemos como todos os registros do banco de dados são retrieved, updated, created, and deleted e como exatamente essas consultas são realizadas?

Para entender tudo isso, podemos simplesmente adicionar uma opção em nossa configuração, que registra o SQL no console. Aqui está a declaração simples que registrará a consulta SQL -

x.LogSqlInConsole = true;

Agora, temos dois registros em nossa tabela de alunos no banco de dados NHibernateDemoDB. Vamos recuperar todos os registros do banco de dados, conforme mostrado no código a seguir.

using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 

   class Program { 
      
      static void Main(string[] args) { 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;			
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
            
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 
      
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory();
      
         using (var session = sefact.OpenSession()) { 
         
            using (var tx = session.BeginTransaction()) { 
               Console.WriteLine("\nFetch the complete list again\n");
               var students = session.CreateCriteria<Student>().List<Student>(); 
      
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
                     student.LastName); 
               } 
               
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

Então, vamos prosseguir e executar este aplicativo novamente, e você verá a seguinte saída -

NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
   this_.FirstMidName as FirstMid3_0_0_ FROM Student this_

Fetch the complete list again

3 Allan Bommer
4 Jerry Lewis

Como você pode ver, o select clausesendo enviado para o banco de dados, é na verdade como uma cláusula que irá recuperar o ID, FirstMidName e LastName. Portanto, tudo isso está sendo enviado para o banco de dados e processado lá, em vez de ter muitos registros devolvidos ao servidor e processados ​​no servidor.

NHibernate Profiler

Outra maneira de ver esses resultados é usar o NHibernate Profiler. NHibernate Profiler é uma ferramenta comercial, mas é muito útil para trabalhar com aplicativos NHibernate. Você pode instalar facilmente o NHibernate Profiler em seu aplicativo a partir do NuGet.

Vamos para o console do NuGet Manager no menu Ferramentas, selecionando NuGet Package Manager → Package Manager Console. Isso abrirá a janela do console do gerenciador de pacotes. Digite o seguinte comando e pressione Enter.

PM> install-package NHibernateProfiler

Ele irá instalar todos os binários necessários para o NHibernate Profiler, uma vez que ele seja instalado com sucesso, você verá a seguinte mensagem.

Você também verá que o NHibernate Profiler é iniciado, uma vez instalado. Exigirá uma licença para usá-lo, mas para fins de demonstração, podemos usar a versão de teste de 30 dias do NHibernate Profiler.

Agora, o NHibernate Profiler está otimizado para trabalhar com aplicativos da web e você verá que ele adicionou App_Start folderno explorador de soluções. Para manter tudo isso simples, exclua a pasta App_Start e também observará que uma instrução é adicionada no início do método Main na classe Program.

App_Start.NHibernateProfilerBootstrapper.PreStart();

Remova esta declaração também e apenas adicione uma chamada simples NHibernateProfiler.Initialize conforme mostrado no código a seguir.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 
   
   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;			
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 

         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()) { 
            
            using (var tx = session.BeginTransaction()){ 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n");
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
                     student.LastName); 
               } 
					
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   
   }
}

Agora, quando você executa o aplicativo, ele enviará dados para o aplicativo NHibernate Profiler.

Você pode ver aqui, temos uma bela exibição que mostra que iniciamos a transação, o que o SQL está fazendo com o banco de dados em um formato agradável.

Portanto, isso é muito útil para determinar o que exatamente está acontecendo dentro de seu aplicativo NHibernate. Torna-se incrivelmente útil quando a aplicação atinge um certo nível de complexidade, onde você precisa de algo mais parecido com um SQL Profiler, mas com o conhecimento de NHibernate.

Neste capítulo, vamos adicionar IntelliSense aos nossos arquivos de mapeamento NHibernate (*.hbm.xml files). Como você observou ao mapear a classe de Aluno do domínio, atualmente não temos o IntelliSense disponível. É muito útil ter oXML schemasacessível. Portanto, neste capítulo, você entenderá como adicionar IntelliSense no Visual Studio para esses arquivos XML do NHibernate.

Abra o arquivo de mapeamento e você verá que a opção de menu XML aparece no menu principal.

Selecione a opção de menu XML → Esquemas… e será exibida a caixa de diálogo Esquemas XML.

Selecione o botão Adicionar… que está no canto superior direito da caixa de diálogo, que abre a caixa de diálogo do arquivo. Agora vá para opackages folder, que está na pasta Solução do seu projeto e você verá os diferentes pacotes incluídos no seu projeto.

Agora, clique duas vezes em NHibernate.4.*** folder e você verá os dois arquivos de esquema (* .xsd) ou arquivos de definição de esquema XML que definem a configuração e o mapeamento do NHibernate.

Selecione esses dois arquivos de esquema e clique no botão Abrir.

Você pode ver que os esquemas NHibernate são adicionados na caixa de diálogo Esquemas XML. Clique no botão OK. Agora, vamos começar uma nova marca de propriedade e você verá que temos IntelliSense completo aqui.

O IntelliSense agora está disponível para você, o que economiza muito tempo durante o mapeamento relacional de objeto.

Neste capítulo, cobriremos os tipos de dados de mapeamento. O mapeamento de entidades é simples, as classes de entidade são sempre mapeadas para tabelas de banco de dados usando<class>, <subclass>, and <joined-subclass>elementos de mapeamento. Os tipos de valor precisam de algo mais, que é onde os tipos de mapeamento são necessários.

O NHibernate é capaz de mapear uma ampla variedade de tipos de dados. Aqui está a lista dos tipos de dados mais comuns que são suportados.

Tipo de mapeamento Tipo .NET System.Data.DbType
Int16 System.Int16 DbType.Int16
Int32 System.Int32 DbType.Int32
Int64 System.Int64 DbType.Int64
solteiro System.Single DbType.Single
em dobro System.Double DbType.Double
Decimal System.Decimal DbType.Decimal
Corda System.String DbType.String
AnsiString System.String DbType.AnsiString
Byte System.Byte DbType.Byte
Caracteres System.Char DbType.StringFixedLength - um caractere
AnsiChar System.Char DbType.AnsiStringFixedLength - um caractere
boleano System.Boolean DbType.Boolean
Guid System.Guid DbType.Guid
PersistentEnum System.Enum (uma enumeração) DbType para o valor subjacente
Verdadeiro falso System.Boolean DbType.AnsiStringFixedLength - 'T' ou 'F'
Sim não System.Boolean DbType.AnsiStringFixedLength - 'Y' ou 'N'
Data hora Data hora DbType.DateTime — ignora milissegundos
Carrapatos System.DateTime DbType.Int64
Intervalo de tempo System.TimeSpan DbType.Int64
Timestamp System.DateTime DbType.DateTime - tão específico quanto o banco de dados suporta
Binário System.Byte [] DbType.Binary
BinaryBlob System.Byte [] DbType.Binary
StringClob System.String DbType.String
Serializável Qualquer System.Object marcado com SerializableAttribute DbType.Binary
CultureInfo System.Globalization.CultureInfo DbType.String - cinco caracteres para cultura
Tipo Tipo de sistema DbType.String contendo o nome qualificado do assembly

A tabela fornecida acima explica em detalhes as dicas abaixo mencionadas.

  • Tudo, desde tipos numéricos simples a strings, que podem ser mapeados de várias maneiras usando varchars, chars etc., bem como blobs de string e toda a variedade de tipos que os bancos de dados suportam.

  • Também é capaz de mapear Booleans, para campos que usam zeros e uns, campos de caracteres que contêm verdadeiro, falso ou T e F.

  • Há uma grande variedade de maneiras de definir como isso mapeia para os valores booleanos de backend no banco de dados.

  • Podemos lidar com o mapeamento de DateTime, incluindo e excluindo compensações de fuso horário, horário de verão, etc.

  • Também podemos mapear enumerations; podemos mapeá-los para strings ou para seus valores numéricos subjacentes.

Vamos dar uma olhada em um exemplo simples no qual temos os mesmos nomes de propriedades no banco de dados e também na classe Aluno.

Agora vamos mudar o FirstMidName para FirstName na classe do aluno, onde não mudaremos a coluna FirstMidName, mas veremos como dizer ao NHibernate para realizar esta conversão. A seguir está a classe do aluno atualizada.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 
  
   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
   }
}

Aqui está a implementação do arquivo de mapeamento NHibernate.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemoApp" 
   namespace = "NHibernateDemoApp"> 
   
   <class name = "Student">
	
      <id name = "ID"> 
         <generator class = "native"/>
      </id> 
   
      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
   </class> 

</hibernate-mapping>

Neste exemplo, suponha que o campo FirstName seja uma string .NET e a coluna FirstMidName seja um SQL nvarchar. Agora, para dizer ao NHibernate como realizar essa conversão, defina o nome igual aFirstName e coluna igual a FirstMidName e especifique o tipo de mapeamento igual a String, que é apropriado para esta conversão particular.

O seguinte é um Program.cs implementação de arquivo.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 

   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
            
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory();
			
         using (var session = sefact.OpenSession()) { 
            
            using (var tx = session.BeginTransaction()) { 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstName,
                     student.LastName); 
               } 
					
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   }
}

Agora, ao executar seu aplicativo, você verá a seguinte saída.

NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_, 
   this_.FirstMidName as FirstMid3_0_0_ FROM Student this_

Fetch the complete list again
3 Allan Bommer
4 Jerry Lewis

Como você pode ver, ele mapeou o nome da propriedade diferente para o nome da coluna no banco de dados.

Vamos dar uma olhada em outro exemplo em que adicionaremos outra propriedade na classe Aluno de enumtipo. Aqui está a implementação da classe Aluno.

using System; 
using System.Collections.Generic; 
using System.Linq; using System.Text; 
using System.Threading.Tasks; 

namespace NHibernateDemoApp { 
   
   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual StudentAcademicStanding AcademicStanding { get; set; } 
   } 
   
   public enum StudentAcademicStanding { 
      Excellent, 
      Good, 
      Fair, 
      Poor, 
      Terrible 
   } 
}

Como você pode ver, essa enumeração tem uma variedade de valores diferentes que pode ter, como Excelente, Bom, Regular, Ruim e Péssimo.

Saltando para o arquivo de mapeamento, você pode ver que cada uma dessas propriedades estão listadas no arquivo de mapeamento, incluindo o recém-adicionado AcademicStanding propriedade.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp"> 
   
   <class name = "Student"> 
	
      <id name = "ID"> 
         <generator class = "native"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 
   </class>  

</hibernate-mapping>

Agora também precisamos alterar o banco de dados também, então vá para o SQL Server Object Explorer, clique com o botão direito do mouse no banco de dados e selecione a opção New Query….

Isso abrirá o editor de consultas e, em seguida, especificará a consulta abaixo.

DROP TABLE [dbo].[Student]

CREATE TABLE [dbo].[Student] ( 
   [ID] INT IDENTITY (1, 1) NOT NULL, 
   [LastName] NVARCHAR (MAX) NULL, 
   [FirstMidName] NVARCHAR (MAX) NULL, 
   [AcademicStanding] NCHAR(10) NULL, 
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC) 
);

Esta consulta eliminará primeiro a tabela do aluno existente e, em seguida, criará uma nova tabela.

Clique no ícone Executar conforme mostrado acima. Assim que a consulta for executada com sucesso, você verá uma mensagem.

Expanda o banco de dados e a lista suspensa Tabela, clique com o botão direito do mouse na mesa do Aluno e selecione Exibir Designer.

Agora, você verá a tabela recém-criada, que também possui a nova propriedade AcademicStanding.

Vamos adicionar dois registros conforme mostrado a seguir Program.cs Arquivo.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;

namespace NHibernateDemoApp { 

   class Program { 
      
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
            
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
         }); 
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()) { 
            using (var tx = session.BeginTransaction()) { 
               
               var student1 = new Student { 
                  ID = 1, 
                  FirstName = "Allan", 
                  LastName = "Bommer",
                  AcademicStanding = StudentAcademicStanding.Excellent 
               };
               
               var student2 = new Student { 
                  ID = 2, 
                  FirstName = "Jerry", 
                  LastName = "Lewis", 
                  AcademicStanding = StudentAcademicStanding.Good 
               };
					
               session.Save(student1); 
               session.Save(student2);
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n");
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName, student.LastName, student.AcademicStanding); 
               } 
					
               tx.Commit(); 
            }
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

Agora vamos executar seu aplicativo e você verá a seguinte saída na janela do console.

Fetch the complete list again

1 Allan Bommer Excellent
2 Jerry Lewis Good

Agora vamos dar uma olhada no banco de dados clicando com o botão direito do mouse na Tabela do Aluno.

Selecione Exibir dados e você verá os dois registros na tabela do aluno, conforme mostrado na captura de tela a seguir.

Você pode ver que dois registros são adicionados e Allan tem AcademicStanding 0 e Jerry tem AcademicStanding 1. Isso ocorre porque em .Net o primeiro valor de enumeração por padrão tem 0, que é excelente se você olhar StudentAcademicStanding. Enquanto no arquivo Student.cs Good é o segundo, ele tem o valor 1.

Neste capítulo, veremos a configuração do NHibernate. Temos diferentes maneiras de configurar o NHibernate. Ele se divide em dois grupos principais

  • Configuração baseada em XML
  • Configuração baseada em código

Configuração Baseada em Código

A configuração baseada em código é construída em NHibernate. Ele foi introduzido em torno do NHibernate 3 e temos usado a configuração de bases de código até agora.

String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;

cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
   Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
   TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
   
   x.Driver<SqlClientDriver>(); 
   x.Dialect<MsSql2008Dialect>(); 
   x.LogSqlInConsole = true; 
}); 

cfg.AddAssembly(Assembly.GetExecutingAssembly());

Todas as configurações são especificadas no código C #. Você pode ver aqui que temos nosso novo objeto de configuração e, em seguida, usamosloquacious configurationque foi introduzido com NHibernate 3.1 para configurar o banco de dados. Qual string de conexão estamos usando, qual banco de dados estamos nos conectando e o dialeto a ser usado. Também adicionamos nosso conjunto de mapeamento diretamente aqui.

Configuração baseada em XML

Se você estiver usando uma configuração baseada em XML, você pode usar um hibernate.cfg.xml arquivo, que é apenas um arquivo xml autônomo usando o esquema NHibernate, ou você pode incorporar essa configuração específica do NHibernate dentro de seu aplicativo ou web.cfg. O nome hibernate.cfg.xml é por padrão, mas podemos usar um nome arbitrário para esse arquivo xml também.

Vamos dar uma olhada na configuração baseada em XML adicionando um novo arquivo xml ao projeto NHibernateDemoApp e chamá-lo de hibernate.cfg.xml.

Insira as seguintes informações no arquivo hibernate.cfg.xml.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2"> 
   <session-factory> 
   
      <property name = "connection.connection_string">
         Data Source = asia13797\\sqlexpress;
         Initial Catalog = NHibernateDemoDB;
         Integrated Security = True;
         Connect Timeout = 15;
         Encrypt = False;
         TrustServerCertificate = False;
         ApplicationIntent = ReadWrite;
         MultiSubnetFailover = False;
      </property> 
      
      <property name = "connection.driver_class">
         NHibernate.Driver.SqlClientDriver
      </property> 
		
      <property name = "dialect">
         NHibernate.Dialect.MsSql2008Dialect
      </property> 
		
      <mapping assembly = "NHibernateDemoApp"/>
		
   </session-factory> 
	
</hibernate-configuration>

Como você pode ver no arquivo xml acima, especificamos a mesma configuração mencionada no C #.

Agora vamos comentar sobre esta configuração do arquivo Program.cs e apenas chamar o Configure() método, que irá carregar o hibernate.cfg.xml arquivo como mostrado abaixo.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection; 

namespace NHibernateDemoApp { 

   class Program { 
      
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         //cfg.DataBaseIntegration(x =>
         
         //{ 
            // x.ConnectionString = "Data Source = asia13797;\\sqlexpress
            Initial Catalog = NHibernateDemoDB;
            Integrated Security = True;
            Connect Timeout = 15;
            Encrypt =False;
            TrustServerCertificate = False;
            ApplicationIntent = ReadWrite;
            MultiSubnetFailover = False"; 
            
            // x.Driver<SqlClientDriver>(); 
            // x.Dialect<MsSql2008Dialect>(); 
            // x.LogSqlInConsole = true; 
         //}); 
         
         //cfg.AddAssembly(Assembly.GetExecutingAssembly());
         cfg.Configure();
         var sefact = cfg.BuildSessionFactory();
			
         using (var session = sefact.OpenSession()) { 
            
            using (var tx = session.BeginTransaction()) { 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName, student.LastName, student.AcademicStanding); 
               } 
					
               tx.Commit(); 
            } 
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

Vamos executar seu aplicativo novamente e você verá a mesma saída.

Fetch the complete list again

1 Allan Bommer Excellent
2 Jerry Lewis Good

Neste capítulo, abordaremos como substituir a configuração do NHibernate. Existem apenas algumas coisas que você precisa ter em mente.

  • Em primeiro lugar, a configuração no NHibernate é aditiva.

  • Portanto, você não precisa apenas usar um único arquivo xml ou não precisa apenas usar a configuração baseada em código ou o NHibernate fluente.

  • Você pode misturar e combinar todos esses métodos, dependendo de como deseja configurar seu aplicativo.

  • O ponto importante a lembrar é que, por último, a configuração vence.

No exemplo a seguir, você pode ver que criamos nosso objeto de configuração, configuramos-o usando a configuração baseada em código e, finalmente, chamamos o cfg.configure() método, que carrega o arquivo hibernate.cfg.xml.

String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;

cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
   Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
   TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
	
   x.Driver<SqlClientDriver>(); 
   x.Dialect<MsSql2008Dialect>(); 
   x.LogSqlInConsole = true; 
}); 

cfg.Configure();
  • Portanto, qualquer coisa dentro de um hibernate.cfg.xml substitui as configurações definidas pela configuração baseada em código.

  • Ao reverter esses dois processos, podemos ter os padrões dentro de hibernate.cfg.xml e, em seguida, fazer nossas substituições dentro de uma configuração baseada em código.

  • Não há nada que exclua se você estiver usando configuração baseada em código e também não há nada que o impeça de usar o arquivo hibernate.cfg.xml.

Vamos dar uma olhada em um exemplo simples no qual substituiremos a configuração usando uma mistura de configuração baseada em xml e baseada em código.

Vamos também mover a string de conexão para o app.config arquivo usando o código a seguir.

<?xml version = "1.0" encoding = "utf-8" ?> 

<configuration> 
   
   <startup> 
      <supportedRuntime version = "v4.0" sku = ".NETFramework,Version = v4.5" /> 
   </startup> 
   
   <connectionStrings> 
      <add name = "default" connectionString = "Data Source =
         asia13797\\sqlexpress;
         Initial Catalog = NHibernateDemoDB;
         Integrated Security = True;
         Connect Timeout = 15;
         Encrypt = False;
         TrustServerCertificate = False;
         ApplicationIntent = ReadWrite;
         MultiSubnetFailover = False"/> 
   </connectionStrings> 

</configuration>

A string de conexão está em algum app.configarquivo com um nome padrão. Agora, precisamos mencionar o nome padrão no arquivo hibernate.cfg.xml em vez da string de conexão.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2"> 

   <session-factory> 
      <property name = "connection.connection_string">default</property> 
		
      <property name = "connection.driver_class">
         NHibernate.Driver.SqlClientDriver
      </property> 
		
      <property name = "dialect">
         NHibernate.Dialect.MsSql2008Dialect
      </property> 
		
      <mapping assembly = "NHibernateDemoApp"/> 
   </session-factory> 

</hibernate-configuration>

Vamos comentar sobre a parte da string de conexão, driver e parte do dialeto da configuração baseada em código, porque o programa irá lê-lo do arquivo hibernate.cfg.xml e o LogSqlInConsole parte permanecerá na configuração baseada em código.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 
   
   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration();
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { //x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            //x.Driver<SqlClientDriver>(); 
            //x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
         }); 
         
         cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
               
               var students = session.CreateCriteria<Student>().List<Student>();
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                  student.FirstName, student.LastName, student.AcademicStanding); 
               } 
					
               tx.Commit(); 
            }
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

Agora, ao executar o aplicativo, você verá que o programa leu o log da configuração baseada em código e outra configuração do arquivo hibernate.cfg.xml.

NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,   
   this_.FirstMidName as FirstMid3_0_0_, this_.AcademicStanding as Academic4_0_0_ FROM
   Student this_

Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good

Agora temos algumas de nossas configurações dentro de nosso hibernate.cfg.xml arquivo, parte dele está dentro da configuração baseada em código e dependendo da ordem de chamada baseada em código versus configure(), podemos alterar qual deles substitui o outro.

Neste capítulo, iremos cobrir a atualização do tamanho do lote. O tamanho do lote permite que vocêcontrol the number of updates que saem em uma única viagem de ida e volta para seu banco de dados para os bancos de dados suportados.

  • O tamanho do lote de atualização foi padronizado a partir do NHibernate 3.2.

  • Mas se você estiver usando uma versão anterior ou precisar ajustar seu aplicativo NHibernate, você deve olhar para o tamanho do lote de atualização, que é um parâmetro muito útil que pode ser usado para ajustar o desempenho do NHibernate.

  • Na verdade, o tamanho do lote controla quantas inserções enviar de um grupo para um banco de dados.

  • No momento, apenas o SQL Server e o Oracle oferecem suporte a essa opção porque o provedor de banco de dados subjacente precisa oferecer suporte ao envio em lote de consultas.

Vamos dar uma olhada em um exemplo simples no qual definimos o tamanho do lote para 10 que irá inserir 10 registros em um conjunto.

cfg.DataBaseIntegration(x => { 
  
   x.ConnectionString = "default"; 
   x.Driver<SqlClientDriver>(); 
   x.Dialect<MsSql2008Dialect>(); 
   x.LogSqlInConsole = true; 
   x.BatchSize = 10; 

});

Aqui está a implementação completa na qual 25 registros serão adicionados ao banco de dados.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp {
   
   class Program {
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
         
            x.Driver>SqlClientDriver<(); 
            x.Dialect>MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory();
			
         using (var session = sefact.OpenSession()) {
			
            using (var tx = session.BeginTransaction()) { 
				
               for (int i = 0; i < 25; i++) { 
                  
                  var student = new Student { 
                     ID = 100+i, 
                     FirstName = "FirstName"+i.ToString(), 
                     LastName = "LastName" + i.ToString(), 
                     AcademicStanding = StudentAcademicStanding.Good 
                  };
						
                  session.Save(student); 
               } 
					
               tx.Commit();
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,student.FirstName,
                     student.LastName, student.AcademicStanding); 
               } 
            } 
				
            Console.ReadLine(); 
         } 
      }
   } 
}

Agora vamos executar seu aplicativo e você verá que todas essas atualizações estão pulando para o perfilador do NHibernate. Temos 26 viagens individuais de ida e volta ao banco de dados, 25 para inserção e uma para recuperação da lista de alunos.

Agora, por que isso? A razão é porque o NHibernate precisa fazer umselect scope identity porque estamos usando a estratégia de geração de identificador nativo no arquivo de mapeamento para ID, conforme mostrado no código a seguir.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" 
   namespace = "NHibernateDemoApp"> 
   
   <class name = "Student"> 

      <id name = "ID"> 
         <generator class = "native"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 
   
   </class> 
</hibernate-mapping>

Portanto, precisamos usar um método diferente, como o guid.combmétodo. Se vamos para guid.comb, precisamos ir até nosso cliente e mudar isso para umguid. Então isso vai funcionar bem. Agora vamos mudar do nativo para guid.comb usando o código a seguir.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly =
   "NHibernateDemoApp" namespace = "NHibernateDemoApp"> 
   <class name = "Student"> 

      <id name = "ID"> 
         <generator class = "guid.comb"/> 
      </id> 

      <property name = "LastName"/> 
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/> 

   </class> 

</hibernate-mapping>

Portanto, é o banco de dados responsável por gerar esses IDs. A única maneira do NHibernate descobrir qual ID foi gerado é selecioná-lo imediatamente depois. Ou então, se tivermos criado um lote de alunos, não será possível coincidir com o ID do aluno que foi criado.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 

   class Student { 
      public virtual Guid ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual StudentAcademicStanding AcademicStanding { get; set; }
   } 
	
   public enum StudentAcademicStanding { 
      Excellent, 
      Good, 
      Fair, 
      Poor, 
      Terrible 
   }
}

Precisamos apenas atualizar nosso banco de dados. Vamos eliminar a tabela do aluno e criar uma nova tabela especificando a seguinte consulta, então vá para o SQL Server Object Explorer e clique com o botão direito no banco de dados e selecione oNew Query… Opção.

Isso abrirá o editor de consultas e, em seguida, especificará a consulta a seguir.

DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] ( 

   -- [ID] INT IDENTITY (1, 1) NOT NULL, 
   [ID] UNIQUEIDENTIFIER NOT NULL, 
   [LastName] NVARCHAR (MAX) NULL, 
   [FirstMidName] NVARCHAR (MAX) NULL, 
   [AcademicStanding] NCHAR(10) NULL, 
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC) 
);

Esta consulta eliminará primeiro a tabela do aluno existente e, em seguida, criará uma nova tabela. Como você pode ver, temos usadoUNIQUEIDENTIFIER em vez de usar uma chave primária inteira como ID.

Execute esta consulta e vá para o Designer view e você verá que agora o ID é criado com um identificador exclusivo, conforme mostrado na imagem a seguir.

Agora precisamos remover o ID do arquivo program.cs, ao inserir os dados, porque agora ele irá gerar o guids para isso automaticamente.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 
   
   class Program { 
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize();
         var cfg = new Configuration();

         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover"; 
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true;
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
				
               for (int i = 0; i > 25; i++) { 
                  
                  var student = new Student { 
                     FirstName = "FirstName"+i.ToString(), 
                     LastName = "LastName" + i.ToString(), 
                     AcademicStanding = StudentAcademicStanding.Good 
                  }; 
                  
                  session.Save(student); 
               } 
					
               tx.Commit(); 
               var students = session.CreateCriteria<Student>().List<Student>(); 
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
                     student.FirstName,student.LastName, student.AcademicStanding);
               } 
            
            }
				
            Console.ReadLine(); 
         } 
      } 
   } 
}

Agora execute o aplicativo novamente e dê uma olhada no profiler NHibernate. Agora, o perfilador do NHibernate, em vez de fazer 26 viagens de ida e volta, fará apenas quatro.

São inseridas dez linhas na tabela, depois outras dez linhas e, posteriormente, as cinco restantes. E após o commit, ele inseriu mais um para recuperar todos os registros.

  • Portanto, é dividido em grupos de dez, da melhor maneira possível.

  • Portanto, se você estiver fazendo muitas inserções, isso pode melhorar drasticamente o desempenho da inserção em seu aplicativo, porque você pode agrupá-las.

  • Isso ocorre porque o NHibernate atribui esses próprios guias usando o guid.comb algoritmo e não precisa depender do banco de dados para fazer isso.

  • Portanto, usar o tamanho do lote é uma ótima maneira de ajustá-lo.

Neste capítulo, iremos cobrir como o cachingfunciona em aplicativos NHibernate. Possui suporte integrado para armazenamento em cache. Parece um recurso simples, mas, na realidade, é um dos recursos mais complexos. Começaremos com o cache de primeiro nível.

Cache de primeiro nível

Este mecanismo de cache é habilitado por padrão no NHibernate e não precisamos fazer nada para trabalhar com o cache. Para entender isso, vamos dar uma olhada em um exemplo simples, como você pode ver que temos dois registros em nosso banco de dados.

Agora, neste exemplo, recuperaremos o aluno cujo ID é 1 e usaremos a mesma consulta de sessão duas vezes, conforme mostrado no código a seguir.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cache; 
using NHibernate.Cfg; 
using NHibernate.Dialect;
using NHibernate.Driver; 
using NHibernate.Linq; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 
   
   class Program { 
      static void Main(string[] args) {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.LogSqlInConsole = true; 
            x.BatchSize = 10; 
         }); 
         
         //cfg.Configure(); 
         
         cfg.Cache(c => { 
            c.UseMinimalPuts = true; 
            c.UseQueryCache = true; 
         }); 
			
         cfg.SessionFactory().Caching .Through<HashtableCacheProvider>()
            .WithDefaultExpiration(1440); 
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
         
         using (var session = sefact.OpenSession()){ 
			
            using (var tx = session.BeginTransaction()) { 
               var studentUsingTheFirstQuery = session.Get<Student>(1);
               var studentUsingTheSecondQuery = session.Get<Student>(1); 
            } 
            
            Console.ReadLine(); 
         } 
      } 
   } 
}

Agora vamos executar este aplicativo e ver o resultado no NHibernate Profiler.

Você ficará surpreso ao ver que o NHibernate dispara apenas uma consulta. É assim que o NHibernate usa o cache de primeiro nível. Quando a primeira consulta é executada, o NHibernate armazenou em cache o aluno com ID = 1 em seu cache de primeiro nível.

Portanto, quando a segunda consulta é executada, o NHibernate primeiro procura a entidade de estudante do cache de primeiro nível com ID = 1, se encontrar essa entidade, o NHibernate sabe disso, não há necessidade de disparar outra consulta para recuperar o mesmo objeto de funcionário novamente .

Neste capítulo, falaremos sobre componentes de mapeamento. No NHibernate,component is a value object. Não tem identidade própria.

  • Um exemplo disso seria um objeto de dinheiro, uma bolsa ou carteira pode conter dinheiro, mas a identidade exata desse dinheiro é irrelevante.

  • Ele não tem sua própria chave primária, mas os próprios componentes são persistentes na mesma tabela que o objeto proprietário.

Vamos dar uma olhada em um exemplo simples em que um aluno tem um endereço, que é um objeto de Location class associado a isso.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace NHibernateDemoApp { 

   class Student { 
      public virtual int ID { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual StudentAcademicStanding AcademicStanding { get; set; } 
      public virtual Location Address { get; set; } 
   }

   public class Location { 
      public virtual string Street { get; set; } 
      public virtual string City { get; set; } 
      public virtual string Province { get; set; } 
      public virtual string Country { get; set; } 
   }
  
   public enum StudentAcademicStanding { 
      Excellent, 
      Good, 
      Fair, 
      Poor, 
      Terrible 
   } 
}

Agora, também precisamos atualizar o banco de dados executando a seguinte consulta, que primeiro eliminará a tabela Aluno e, em seguida, criará uma nova tabela que também conterá uma coluna para a classe Localização.

DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] ( 

   [ID] INT IDENTITY (1, 1) NOT NULL, 
   [LastName] NVARCHAR (MAX) NULL, 
   [FirstMidName] NVARCHAR (MAX) NULL, 
   [AcademicStanding] NCHAR(10) NULL, 
   [Street] NVARCHAR (100) NULL, 
   [City] NVARCHAR (100) NULL, 
   [Province] NVARCHAR (100) NULL, 
   [Country] NVARCHAR (100) NULL, 
   CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC) 

);

Agora, para mapear aquelas colunas que não são diretamente parte da classe do aluno, mas são propriedades da classe Local e o objeto da classe Local é definido na classe do aluno. Precisamos de um componente para mapeá-lo corretamente. Vamos criar um componente emstudent.hbm.xml arquivo conforme mostrado no código a seguir.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp"> 

   <class name = "Student"> 
      <id name = "ID"> 
         <generator class = "native"/>
      </id> 
   
      <property name = "LastName"/> 
		
      <property name = "FirstName" column = "FirstMidName" type = "String"/> 
      <property name = "AcademicStanding"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 
   
   </class> 
</hibernate-mapping>

Este componente é o Endereço e tem essas propriedades diferentes nele. Com essas informações, o NHibernate agora tem o suficiente para mapear isso.

Agora, aqui está o arquivo Program.cs no qual um novo objeto de aluno é criado e inicializado e então salvo no banco de dados. Em seguida, ele recuperará a lista do banco de dados.

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cache; 
using NHibernate.Caches.SysCache; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq; 

using System; 
using System.Linq; 
using System.Reflection;
namespace NHibernateDemoApp { 

   class Program {
	
      static void Main(string[] args) { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration();

         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;			
         
         cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source + 
            Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
            TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
				
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
         }); 
         
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         var sefact = cfg.BuildSessionFactory(); 
			
         using (var session = sefact.OpenSession()) { 
			
            using (var tx = session.BeginTransaction()) { 
               
               var student1 = new Student { 
                  ID = 1, 
                  FirstName = "Allan", 
                  LastName = "Bommer", 
                  AcademicStanding = StudentAcademicStanding.Poor, 
                  
                  Address = new Location { 
                     Street = "123 Street", 
                     City = "Lahore", 
                     Province = "Punjab", 
                     Country = "Pakistan" 
                  } 
               }; 
					
               session.Save(student1); 
               tx.Commit(); 
               var students = session.Query<Student>().ToList<Student>();
               Console.WriteLine("\nFetch the complete list again\n"); 
               
               foreach (var student in students) { 
                  Console.WriteLine("{0} \t{1} \t{2} \t{3} \t{4} \t{5} \t{6} \t{7}", 
                     student.ID, 
                     student.FirstName, 
                     student.LastName, 
                     student.AcademicStanding, 
                     student.Address.Street, 
                     student.Address.City, 
                     student.Address.Province, 
                     student.Address.Country
                  ); 
               } 
            } 
            Console.ReadLine(); 
         } 
      }
   } 
}

Agora podemos executar este aplicativo e o NHibernate pode salvar esses valores no banco de dados. Ao executar o aplicativo, você verá a seguinte saída.

Fetch the complete list again

2 Allan Bommer Poor 123 Street Lahore Punjab Pakistan

Aqui estão os valores no banco de dados.

Os componentes nos permitem separar colunas que estão em uma tabela de banco de dados em sua própria classe separada.

  • A outra coisa a se notar aqui é porque o Location é uma classe, não uma entidade.

  • É um objeto do tipo valor e não possui sua própria chave primária.

  • Ele é salvo na mesma tabela do Aluno que o contém.

  • É por isso que estamos usando o componente aqui.

  • Isso permite muita flexibilidade para alterar nossa camada de classe, como nossas classes são definidas versus como nosso banco de dados é organizado.

Neste capítulo, veremos os relacionamentos no NHibernate. Vamos voltar nossa atenção para como podemos entender os relacionamentos no NHibernate. A maneira mais fácil é pensar sobre os relacionamentos da perspectiva do banco de dados.

  • Criaremos primeiro um novo aplicativo no qual criaremos alguns relacionamentos entre o cliente e as entidades do pedido.

  • O primeiro relacionamento que veremos é um relacionamento de coleção clássico.

  • Temos um cliente com uma coleção de pedidos.

  • Este é um relacionamento de um para muitos e é representado no banco de dados por 2 tabelas e há um ID do cliente na tabela de pedidos e temos um relacionamento de chave estrangeira de volta para o cliente.

Primeiro, precisamos criar um banco de dados e duas tabelas Customer e Order. Você pode criar isso especificando a seguinte consulta no SQL Server Explorer.

USE [master] 
GO 
CREATE DATABASE [NHibernateDemo] 
GO 
USE [NHibernateDemo] 
GO

CREATE TABLE [dbo].[Customer]( 
   [Id] [uniqueidentifier] NOT NULL, 
   [FirstName] [nvarchar](100) NOT NULL, 
   [LastName] [nvarchar](100) NOT NULL, 
   [Points] [int] NULL, [HasGoldStatus] [bit] NULL, 
   [MemberSince] [date] NULL, 
   [CreditRating] [nchar](20) NULL, 
   [AverageRating] [decimal](18, 4) NULL, 
   [Street] [nvarchar](100) NULL, 
   [City] [nvarchar](100) NULL, 
   [Province] [nvarchar](100) NULL, 
   [Country] [nvarchar](100) NULL,
   PRIMARY KEY CLUSTERED ([Id] ASC) 
) 

GO 
CREATE TABLE [dbo].[Order]( 
   [Id] [uniqueidentifier] NOT NULL, 
   [CustomerId] [uniqueidentifier] NULL, 
   [Ordered] [datetime] NULL, 
   [Shipped] [datetime] NULL, 
   [Street] [nvarchar](100) NULL, 
   [City] [nvarchar](100) NULL, 
   [Province] [nvarchar](100) NULL, 
   [Country] [nvarchar](100) NULL, 
   PRIMARY KEY CLUSTERED ([Id] ASC) 
) 
GO

Ele criará duas tabelas no banco de dados. A imagem a seguir mostra a Tabela de Clientes.

A imagem a seguir mostra a Tabela de Pedidos na qual você pode ver o relacionamento da chave estrangeira de volta para o cliente.

Precisamos definir a string de conexão no app.config arquivo, aqui está a implementação do arquivo app.config.

<?xml version = "1.0" encoding = "utf-8" ?> 
<configuration> 
   
   <connectionStrings> 
      <add name = "default" connectionString = "Data Source =
         (localdb)\MSSQLLocalDB;Initial Catalog = NHibernateDemo;Integrated Security =
         True;Connect Timeout = 30;Encrypt = False;TrustServerCertificate = False;
         ApplicationIntent = ReadWrite;MultiSubnetFailover = False"/> 
   </connectionStrings> 

</configuration>

Para instalar o NHibernate em seu aplicativo, execute o seguinte comando na janela do console do NuGet Manager.

install-package NHibernate

Para definir a configuração do NHibernate, precisamos definir a configuração em hibernate.cfg.xml arquivo conforme mostrado no código a seguir.

<xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2"> 
   
   <session-factory> 
      <property name = "connection.connection_string_name">default</property>
		
      <property name = "connection.driver_class">
         NHibernate.Driver.SqlClientDriver 
      </property> 
		
      <property name = "dialect">
         NHibernate.Dialect.MsSql2008Dialect
      </property> 
		
      <property name = "show_sql">true</property> 
   </session-factory> 

</hibernate-configuration>

Neste exemplo, estaremos trabalhando com duas classes de domínio, Cliente e Pedido.

Aqui está a implementação do arquivo Customer.cs no qual temos duas classes, uma é a classe Customer e outra é a classe Location na qual o objeto é usado como um endereço na classe Customer.

using System; 
using System.Text; 
using Iesi.Collections.Generic;

namespace NHibernateDemo { 

   public class Customer { 
      
      public Customer() { 
         MemberSince = DateTime.UtcNow; 
         Orders = new HashedSet<Order>(); 
      } 
      
      public virtual Guid Id { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual double AverageRating { get; set; } 
      public virtual int Points { get; set; } 
		
      public virtual bool HasGoldStatus { get; set; }
      public virtual DateTime MemberSince { get; set; } 
      public virtual CustomerCreditRating CreditRating { get; set; } 
      public virtual Location Address { get; set; }
		
      public virtual ISet<Order> Orders { get; set; }
      public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
      
      public override string ToString() { 
         var result = new StringBuilder();
			
         result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
            {4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
            {8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
            CreditRating, MemberSince.Kind, AverageRating);
            result.AppendLine("\tOrders:"); 
         
         foreach(var order in Orders) { 
            result.AppendLine("\t\t" + order); 
         } 
			
         return result.ToString(); 
      } 
   }
   
   public class Location { 
      public virtual string Street { get; set; } 
      public virtual string City { get; set; } 
      public virtual string Province { get; set; } 
      public virtual string Country { get; set; } 
   }
   
   public enum CustomerCreditRating { 
      Excellent,
      VeryVeryGood, 
      VeryGood, 
      Good, 
      Neutral, 
      Poor, 
      Terrible 
   } 
}

Aqui está o arquivo de mapeamento Customer.hbm.xml em que a classe Customer é mapeada para a tabela Customer.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo" 
   namespace = "NHibernateDemo"> 
	
   <class name = "Customer"> 
   
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 

      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 

   </class> 
</hibernate-mapping>

Também temos uma classe de pedido e aqui está a implementação de Order.cs Arquivo.

using System; using Iesi.Collections.Generic;

namespace NHibernateDemo { 

   public class Order { 
      
      public virtual Guid Id { get; set; } 
      public virtual DateTime Ordered { get; set; } 
      public virtual DateTime? Shipped { get; set; }
      public virtual Location ShipTo { get; set; } 
      public virtual Customer Customer { get; set; }
      
      public override string ToString() { 
         return string.Format("Order Id: {0}", Id); 
      } 
   } 
}

Relacionamento Muitos para Um

Também precisamos mapear a classe Order para a tabela Order no banco de dados, então aqui está a implementação do Order.hbm.xml Arquivo.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo" 
   namespace = "NHibernateDemo"> 

   <class name = "Order" table = "`Order`"> 
   
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
		
      <property name = "Ordered"/> 
      <property name = "Shipped"/> 
   
      <component name = "ShipTo"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 

      <!--<many-to-one name = "Customer" column = "CustomerId" cascade =
         "save-update"/>--> 
			
   </class> 
</hibernate-mapping>

Relacionamento de um para muitos

Aqui, vamos dar uma olhada em um relacionamento um para muitos, neste caso, entre o cliente e os pedidos. Temos nosso cliente aqui, estamos criando um novo e você pode ver que a coleção foi inicializada com o seguinte par de pedidos.

private static Customer CreateCustomer() { 
   
   var customer = new Customer { 
      FirstName = "John", 
      LastName = "Doe", 
      Points = 100, 
      HasGoldStatus = true, 
      MemberSince = new DateTime(2012, 1, 1), 
      CreditRating = CustomerCreditRating.Good, 
      AverageRating = 42.42424242, 
      Address = CreateLocation() 
   }; 
   
   var order1 = new Order { 
      Ordered = DateTime.Now 
   }; 
   
   customer.AddOrder(order1); 
   var order2 = new Order { 
      Ordered = DateTime.Now.AddDays(-1), 
      Shipped = DateTime.Now, 
      ShipTo = CreateLocation() 
   }; 
   
   customer.AddOrder(order2); 
   return customer; 
}

Então vamos criar um novo cliente e salvá-lo, depois de salvá-lo vamos encontrar o ID e recarregá-lo em outra sessão no método Main conforme mostrado no programa a seguir.

private static void Main() { 

   var cfg = ConfigureNHibernate(); 
   var sessionFactory = cfg.BuildSessionFactory();
   
   Guid id; 
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) { 
      var newCustomer = CreateCustomer(); 
      Console.WriteLine("New Customer:"); 
      Console.WriteLine(newCustomer);
      session.Save(newCustomer); 
      id = newCustomer.Id; 
      tx.Commit(); 
   }
   
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) { 
      var reloaded = session.Load<Customer>(id); 
      Console.WriteLine("Reloaded:"); 
      Console.WriteLine(reloaded); 
      tx.Commit(); 
   }
   
   Console.WriteLine("Press <ENTER> to exit..."); 
   Console.ReadLine(); 
}

Aqui está o completo Program.cs implementação de arquivo.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo {
 
   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         
         Guid id; 
         using(var session = sessionFactory.OpenSession())
			
         using(var tx = session.BeginTransaction()) { 
            var newCustomer = CreateCustomer(); 
            Console.WriteLine("New Customer:"); 
            Console.WriteLine(newCustomer); 
            session.Save(newCustomer); 
            id = newCustomer.Id; 
            tx.Commit(); 
         } 
         
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) { 
            var reloaded = session.Load<Customer>(id); 
            Console.WriteLine("Reloaded:"); 
            Console.WriteLine(reloaded); 
            tx.Commit();
         }
         
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine();
      }
      
      private static Customer CreateCustomer() { 
		
         var customer = new Customer { 
            FirstName = "John", 
            LastName = "Doe", 
            Points = 100, 
            HasGoldStatus = true, 
            MemberSince = new DateTime(2012, 1, 1), 
            CreditRating = CustomerCreditRating.Good, 
            AverageRating = 42.42424242, 
            Address = CreateLocation() 
         }; 
         
         var order1 = new Order { 
            Ordered = DateTime.Now
         }; 
         
         customer.AddOrder(order1); 
			
         var order2 = new Order { 
            Ordered = DateTime.Now.AddDays(-1), 
            Shipped = DateTime.Now, 
            ShipTo = CreateLocation() 
         }; 
         
         customer.AddOrder(order2); 
         return customer; 
      } 
      
      private static Location CreateLocation() { 
		
         return new Location { 
            Street = "123 Somewhere Avenue", 
            City = "Nowhere", 
            Province = "Alberta", 
            Country = "Canada" 
         }; 
      } 
      
      private static Configuration ConfigureNHibernate() { 
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x =&ht; { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Ao executar este aplicativo, você verá a seguinte saída.

New Customer:

John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (9b0fcf10-83f6-4f39-bda5-a5b800ede2ba)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
Press <ENTER> to exit...

Como você pode ver, inicialmente o cliente tem 2 pedidos, mas quando o recarregamos, não há pedidos à vista. Se você olhar paracustomer.hbm.xmlarquivo, você pode ver aqui que não mapeamos a coleção real de pedidos. Então o NHibernate não sabe nada sobre isso. Vamos adicionar isso.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" 
   assembly = "NHibernateDemo" namespace = "NHibernateDemo">
	
   <class name = "Customer"> 
      
      <id name = "Id">
         <generator class = "guid.comb"/> 
      </id> 
      
      <property name = "FirstName"/>
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Este é um conjunto e o nome dessa coleção é 'Pedidos', que é armazenado em uma tabela chamada pedido. Precisamos especificar uma chave que é o nome da chave estrangeira ou para encontrar pedidos. Esses pedidos são identificados ou pertencem a um cliente por meio do ID do cliente. E então eu tenho que observar que este é um relacionamento um-para-muitos e é com a classe de pedido.

Também precisamos alterar ligeiramente o método Principal, salvando os novos pedidos do cliente no banco de dados, assim como mostrado no programa a seguir.

private static void Main() { 

   var cfg = ConfigureNHibernate(); 
   var sessionFactory = cfg.BuildSessionFactory();
   
   Guid id; 
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) {
      var newCustomer = CreateCustomer(); 
      Console.WriteLine("New Customer:"); 
      Console.WriteLine(newCustomer);
      session.Save(newCustomer); 
      
      foreach (var order in newCustomer.Orders) { 
         session.Save(order); 
      } 
		
      id = newCustomer.Id; 
      tx.Commit(); 
   }
   
   using(var session = sessionFactory.OpenSession()) 
	
   using(var tx = session.BeginTransaction()) { 
      var reloaded = session.Load<Customer>(id); 
      Console.WriteLine("The orders were ordered by: "); 
      
      foreach (var order in reloaded.Orders) { 
         Console.WriteLine(order.Customer); 
      } 
		
      tx.Commit(); 
   }
   Console.WriteLine("Press <ENTER> to exit..."); Console.ReadLine();
}

Também especificamos qual cliente solicitou aquele produto específico. Portanto, precisamos criar um relacionamento muitos para um para relacionar esse pedido ao cliente.

Então, vamos para o Order.hbm.xml e adicione muitos-para-um e nomeie o campo do cliente e a coluna com o ID do cliente.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
	
   <class name = "Order" table = "`Order`">
      
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id>
      
      <property name = "Ordered"/> 
      <property name = "Shipped"/> 
      
      <component name = "ShipTo"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 

      <many-to-one name = "Customer" column = "CustomerId"/> 
		
   </class> 
</hibernate-mapping>

Vamos executar este aplicativo novamente e agora você verá a seguinte saída.

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
      Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3

The orders were ordered by:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
      Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3

John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
      Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
		
Press <ENTER> to exit...

Neste capítulo, abordaremos como representar coleções. Existem diferentes tipos de coleções que podemos usar no NHibernate, como -

  • Lists
  • Sets
  • Bags

Agora, da perspectiva do .NET, geralmente lidamos com listas ou como estruturas de dados muito simples, listas, dicionários. .NET não tem uma grande variedade de tipos de coleção diferentes. Então, por que o NHibernate precisa de todos esses tipos diferentes? Ele realmente volta para o banco de dados.

Lista

  • Uma lista é uma coleção ordenada de elementos que não são necessariamente exclusivos.

  • Podemos mapear isso usando o IList <T>.

  • Portanto, embora possamos convencionalmente ter uma lista de endereços e, do ponto de vista da aplicação, saibamos que os elementos são únicos, nada na lista nos impede de inserir elementos duplicados nessa lista.

Conjunto

  • Um conjunto é uma coleção não ordenada de elementos únicos. Se você tentar inserir 2 elementos duplicados em um conjunto, ele lançará uma exceção.

  • Não há nada específico no NHibernate sobre isso.

  • É apenas uma maneira conveniente de ter uma implementação de conjunto genérico. Se você estiver no .NET 4, pode usar o novoHashSet <T> para representá-los, mas na maioria dos aplicativos NHibernate, representamos que este é um ISet.

  • É um não ordenado, se você puxar de volta uma lista de endereços de um banco de dados ou uma lista de pedidos, você não sabe em que ordem eles estão vindo, a menos que você coloque um pedido específico por cláusula.

  • Portanto, em geral, os dados que você está retirando de um banco de dados são conjuntos.

  • Eles são coleções exclusivas de elementos não ordenados.

Bolsa

  • Outra coleção comum que veremos no mundo do banco de dados é uma bolsa, que é exatamente como um conjunto, exceto que pode ter elementos duplicados.

  • No mundo .NET, representamos isso por um IList.

Conjuntos são provavelmente os mais comuns, mas você verá listas e bolsas também, dependendo de sua aplicação. Vamos dar uma olhada em um abaixocustomer.hbm.xml arquivo do último capítulo em que as ordens de conjunto são definidas.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo" 
   namespace = "NHibernateDemo"> 
	
   <class name = "Customer"> 
      
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Como você pode ver, mapeamos a coleção de pedidos como um conjunto. Lembre-se de que um conjunto é uma coleção não ordenada de elementos únicos.

Agora, se você observar a classe Customer, verá que a propriedade Orders é definida com um ISet, conforme mostrado no programa a seguir.

public virtual ISet<Order> Orders { get; set; }

Agora, quando este aplicativo for executado, você verá a seguinte saída.

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7

The orders were ordered by:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7

John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
      Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
		
Press <ENTER> to exit...

Se os itens na coleção não precisassem ser exclusivos, se você pudesse ter vários pedidos com a mesma chave primária ocorrendo várias vezes nesta coleção, isso seria melhor mapeado como uma bolsa, conforme mostrado no programa a seguir.

<bag name = "Orders" table = "`Order`"> 
   <key column = "CustomerId"/> 
   <one-to-many class = "Order"/> 
</bag>

Agora, se você executar este aplicativo, obterá uma exceção porque se dermos uma olhada na classe do cliente, você notará que os pedidos estão marcados como um ISet no código C #.

Portanto, também precisaremos mudar isso para um IList e, aqui, precisaríamos mudar de HashSet para uma Lista no construtor.

public class Customer { 
   public Customer() { 
      MemberSince = DateTime.UtcNow; 
      Orders = new List<Order>(); 
   } 
	
   public virtual Guid Id { get; set; } 
   public virtual string FirstName { get; set; } 
   public virtual string LastName { get; set; } 
   public virtual double AverageRating { get; set; } 
   public virtual int Points { get; set; } 
	
   public virtual bool HasGoldStatus { get; set; } 
   public virtual DateTime MemberSince { get; set; } 
   public virtual CustomerCreditRating CreditRating { get; set; } 
   public virtual Location Address { get; set; }
   public virtual IList<Order> Orders { get; set; }
   public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
   
   public override string ToString() { 
      var result = new StringBuilder(); 
		
      result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
         {4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
         {8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
         CreditRating, MemberSince.Kind, AverageRating); result.AppendLine("\tOrders:"); 
      
      foreach(var order in Orders) { 
         result.AppendLine("\t\t" + order); 
      } 
		
      return result.ToString(); 
   } 
}

Ao executar o aplicativo, você verá o mesmo comportamento. Mas agora podemos ter um pedido ocorrendo várias vezes na mesma coleção.

John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287

The orders were ordered by:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287

John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
      Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
		
Press <ENTER> to exit...

Neste capítulo, abordaremos como usar o recurso Cascade. Se você tiver um conjunto ou coleção de itens ou um relacionamento entre duas classes, como nosso cliente e pedido, e tiver um relacionamento de chave estrangeira. Se excluirmos o cliente por padrão, o NHibernate não faz nada com os objetos filho, então aqueles que pertencem a esse cliente e nós podemos estar deixando os pedidos órfãos.

  • Também podemos estar violando as restrições de chave estrangeira, portanto, podemos usar a noção de cascatas.

  • Por padrão, NHibernate não cascata operações para objetos filho.

  • A razão para isso é que você pode ter relacionamentos como um cliente com um endereço de entrega padrão e esse endereço de entrega é compartilhado com muitos clientes diferentes.

  • Portanto, você não gostaria de expandir esse relacionamento necessariamente porque outros clientes ainda estão se referindo a ele.

  • Portanto, toda a noção de cascatas é dizer ao NHibernate como lidar com suas entidades filhas.

Existem diferentes opções para cascateamento, que são as seguintes -

  • none - que é o padrão e significa sem cascata.

  • all - que vai salvar, atualizar e excluir em cascata.

  • save-update - ele se espalhará, salvará e atualizará.

  • delete - ele fará exclusões em cascata.

  • all-delete-orphan - é um nome especial que é usado com bastante frequência e é o mesmo que Todos, exceto, se encontrar Deletar linhas órfãs, ele as deleta também.

Você pode especificar o padrão em seu hbm.xml , para que você possa fornecer uma cascata padrão naquele elemento de mapeamento do Hibernate ou também pode especificá-lo para coleções e relacionamentos específicos, como muitos-para-um.

Vamos dar uma olhada em cascatas de exemplo simples, vamos corrigir o problema no programa, onde temos que cascatear manualmente o salvamento para os pedidos, conforme mostrado no código a seguir.

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) { 
   var newCustomer = CreateCustomer(); 
   Console.WriteLine("New Customer:"); 
   Console.WriteLine(newCustomer); 
   session.Save(newCustomer); 
	
   foreach (var order in newCustomer.Orders) { 
      session.Save(order); 
   } 
	
   id = newCustomer.Id; 
   tx.Commit(); 
}

No snippet de código acima, você pode ver que salvamos manualmente todos os pedidos do cliente. Agora vamos remover o código em cascata manual no qual todos os pedidos são salvos.

using(var session = sessionFactory.OpenSession())
 
using(var tx = session.BeginTransaction()) { 
   var newCustomer = CreateCustomer(); 
   Console.WriteLine("New Customer:"); 
   Console.WriteLine(newCustomer);
	
   session.Save(newCustomer); 
   id = newCustomer.Id; 
   tx.Commit(); 
}

Precisamos especificar a opção de cascata em customer.hbm.xml.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
	
   <class name = "Customer"> 
   
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
      
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>
  • Agora, os pedidos pertencem totalmente ao cliente. Portanto, se os clientes fossem excluídos do banco de dados, nosso aplicativo aqui desejaria excluir todos esses pedidos, incluindo qualquer um que possa ter ficado órfão.

  • Vai acabar fazendo um delete. Com isso, ele dirá excluir da tabela de pedidos, onde o ID do cliente é igual ao cliente que você está excluindo.

  • Portanto, você pode realmente cascatear essas exclusões. Então com oAll, ele salvará, atualizará e excluirá.

Agora, ao executar este aplicativo, você verá a seguinte saída.

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134

The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134

John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
		
Press <ENTER> to exit...

Como você pode ver, excluímos o código do programa que foi colocado em cascata manualmente e nosso aplicativo ainda está funcionando.

Portanto, dependendo do seu relacionamento, você pode querer colocá-los em cascata. Agora, vamos dar uma olhada em um relacionamento em cascata diferente. Vamos paraOrder.hbm.xml arquivo e podemos cascatear esse relacionamento muitos para um.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
   
   <class name = "Order" table = "`Order`"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 

      <property name = "Ordered"/> 
      <property name = "Shipped"/> 
      
      <component name = "ShipTo"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component> 
      
      <many-to-one name = "Customer" column = "CustomerId" cascade = "save-update"/>
		
   </class> 
</hibernate-mapping>

Portanto, se criarmos um novo pedido e houver um novo cliente vinculado a ele e dissermos, salve esse pedido, podemos querer colocá-lo em cascata. Mas uma coisa que provavelmente não gostaríamos de fazer é excluir um pedido para excluir o cliente correspondente.

Portanto, aqui, gostaríamos de fazer uma atualização de salvamento, portanto, usando uma atualização de salvamento, ele irá cascatear quaisquer salvamentos ou atualizações para aquele cliente. Portanto, se conseguirmos um novo cliente ou se estivermos mudando o cliente, isso será uma cascata. Se for uma exclusão, não será excluída do banco de dados.

Então, rodando nosso aplicativo novamente, tudo ainda funciona conforme o esperado.

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134

The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
      John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
		
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
      Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
		
Press <ENTER> to exit...

Agora você deve dar uma olhada em seu aplicativo, lembre-se de que o padrão é Nenhum e você deve pensar sobre suas entidades e seus relacionamentos entre eles para determinar as cascatas apropriadas para cada uma de suas entidades, bem como cada um de seus relacionamentos nesse banco de dados.

Neste capítulo, abordaremos o recurso de carregamento lento. É um conceito totalmente diferente por padrão e o NHibernate não tem carregamento lento, por exemplo, se você carregar um cliente, ele não carregará todos os pedidos.

  • A coleção de pedidos será carregada sob demanda.

  • Qualquer associação, seja um muitos-para-um ou uma coleção, é carregada lentamente por padrão, requer um Open ISession.

  • Se você tiver fechado sua sessão ou se tiver confirmado sua transação, poderá obter uma exceção de carregamento lento que não pode puxar esses objetos adicionais.

  • Você deve ter cuidado com o carregamento lento e com a quantidade de dados de que realmente precisa.

  • Você pode desativar o carregamento lento para uma associação inteira ou colocar lazy igual a false ou também pode especificar uma estratégia de busca.

Aqui está o Program.cs implementação de arquivo.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         
         Guid id; 
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) {
            var newCustomer = CreateCustomer(); 
            Console.WriteLine("New Customer:"); 
            Console.WriteLine(newCustomer); 
            session.Save(newCustomer); 
            id = newCustomer.Id; 
            tx.Commit(); 
         }
         
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) { 
            var reloaded = session.Load<Customer>(id); 
            Console.WriteLine("Reloaded:"); 
            Console.WriteLine(reloaded); 
            Console.WriteLine("The orders were ordered by: "); 
            
            foreach (var order in reloaded.Orders) { 
               Console.WriteLine(order.Customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Customer CreateCustomer() { 
         
         var customer = new Customer { 
            FirstName = "John", 
            LastName = "Doe", 
            Points =100, 
            HasGoldStatus = true, 
            MemberSince = new DateTime(2012, 1, 1),
            CreditRating = CustomerCreditRating.Good,
            AverageRating = 42.42424242, 
            Address = CreateLocation() 
         }; 
			
         var order1 = new Order { Ordered = DateTime.Now }; 
         customer.AddOrder(order1); 
         
         var order2 = new Order { 
            Ordered = DateTime.Now.AddDays(-1), 
            Shipped = DateTime.Now, 
            ShipTo = CreateLocation() 
         }; 
			
         customer.AddOrder(order2); return customer; 
      }
		
      private static Location CreateLocation() { 
         return new Location { 
            Street = "123 Somewhere Avenue", 
            City = "Nowhere", 
            Province = "Alberta", 
            Country = "Canada" 
         }; 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect<(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10;
            x.BatchSize = 10;
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Para entender isso, vamos executar o aplicativo e dar uma olhada no NHibernate Profiler.

Como você pode ver, temos o Select From Customer, dado um determinado ID de cliente e também temos outra tabela Select From Orders, quando ela realmente acessa a coleção daquele cliente.

Portanto, temos 2 viagens de ida e volta para o banco de dados. Agora, às vezes, gostaríamos de otimizar isso. Para fazer isso, vamos para ocustomer.hbm.xml arquivo e adicione uma estratégia de busca e peça a ele para fazer uma busca de junção.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
   
   <class name = "Customer"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan" 
         fetch = "join"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Como você pode ver que não alteramos nenhum código em nosso aplicativo, apenas adicionamos uma estratégia de busca no customer.hbm.xml. Vamos executar este aplicativo novamente, ele ainda se comporta exatamente da mesma maneira. Vejamos NHibernate Profiler.

  • Antes, o programa fazia duas idas e voltas ao banco de dados, agora, ele só tem uma e isso porque está fazendo uma junção externa esquerda aqui.

  • Podemos ver que ele está fazendo uma junção externa esquerda entre a tabela de clientes e a tabela de pedidos com base no ID do cliente e, portanto, é capaz de carregar todas essas informações de uma vez.

  • Salvamos 1 viagem de ida e volta para o banco de dados.

  • O lado negativo é que as informações do cliente serão duplicadas em ambas as linhas e é assim que funciona uma junção externa esquerda SQL.

  • Portanto, com a estratégia de busca, estamos recuperando um pouco mais de dados e salvando uma viagem de ida e volta.

Você também pode fazer isso no nível da consulta, então vamos para o Program.cs arquivo e veja o exemplo recarregado mais simples.

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) { 
   //var query = from customer in session.Query<Customer>() 
   // select customer; 
   //var reloaded = query.Fetch(x => x.Orders).ToList();
	
   var reloaded = session.Load<Customer>(id); 
   Console.WriteLine("Reloaded:"); 
   Console.WriteLine(reloaded); 
   Console.WriteLine("The orders were ordered by: "); 
   
   foreach (var order in reloaded.Orders) { 
      Console.WriteLine(order.Customer); 
   } 
	
   tx.Commit(); 
}

Aqui, estamos fazendo uma carga pelo cliente. Agora vamos alterá-lo para uma consulta e usaremos uma consulta de link conforme mostrado no código a seguir.

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) {
   var query = from customer in session.Query<Customer>() 
   where customer.Id == id select customer; 
   var reloaded = query.Fetch(x => x.Orders).ToList().First();
	
   Console.WriteLine("Reloaded:"); 
   Console.WriteLine(reloaded); 
	
   tx.Commit();
}

Vamos também remover a estratégia de busca do customer.hbm.xml Arquivo.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 

   <class name = "Customer"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/>
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
   
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
   
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Vamos executar este aplicativo novamente e você verá a seguinte saída.

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (6ebacd17-f9ba-4ad8-9817-a5bb01112a5a)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 16a6596b-d56e-41c7-9681-a5bb01112a60
      Order Id: d41d615b-0f21-4032-81db-a5bb01112a61
		
Press <ENTER> to exit...

Agora, vamos dar uma olhada no NHibernate Profiler, você pode ver que temos essa busca de junção ansiosa acontecendo mais uma vez, mas desta vez, é baseado na consulta.

Neste capítulo, abordaremos outro recurso que são os relacionamentos inversos. É uma opção divertida que você verá na coleção que é inversamente igual a true e também confunde muitos desenvolvedores. Então, vamos falar sobre essa opção. Para entender isso, você realmente precisa pensar sobre o modelo relacional. Digamos que você tenha associações bidirecionais usando uma única chave estrangeira.

  • Do ponto de vista relacional, você tem uma chave estrangeira e ela representa o cliente para pedido e os pedidos para cliente.

  • No modelo OO, você tem associações unidirecionais usando essas referências.

  • Não há nada que diga que duas associações unidirecionais representam a mesma associação bidirecional no banco de dados.

  • O problema aqui é que o NHibernate não tem informações suficientes para saber que customer.orders e order.customer representam o mesmo relacionamento no banco de dados.

  • Precisamos fornecer inverse equals true como uma dica, é porque as associações unidirecionais estão usando os mesmos dados.

  • Se tentarmos salvar esses relacionamentos que possuem 2 referências a eles, o NHibernate tentará atualizar essa referência duas vezes.

  • Na verdade, ele fará uma viagem extra de ida e volta ao banco de dados e também terá 2 atualizações para aquela chave estrangeira.

  • O inverso igual a verdadeiro diz ao NHibernate qual lado do relacionamento deve ser ignorado.

  • Quando você a aplica ao lado da coleção, o NHibernate sempre atualiza a chave estrangeira do outro lado, do lado do objeto filho.

  • Então, temos apenas uma atualização para essa chave estrangeira e não temos atualizações adicionais para esses dados.

  • Isso nos permite evitar essas atualizações duplicadas na chave estrangeira e também nos ajuda a evitar violações de chave estrangeira.

Vamos dar uma olhada no customer.cs arquivo no qual você verá o AddOrdere a ideia aqui é que agora temos esse ponteiro de volta do pedido de volta ao cliente e ele precisa ser configurado. Portanto, quando um pedido é adicionado a um cliente, o ponteiro de retorno desse cliente é definido, caso contrário, seria nulo, portanto, precisamos disso para mantê-lo conectado corretamente no gráfico do objeto.

using System; 
using System.Text; 
using Iesi.Collections.Generic;

namespace NHibernateDemo {
 
   public class Customer { 
      
      public Customer() {
         MemberSince = DateTime.UtcNow; Orders = new HashedSet<Order>();
      } 
      
      public virtual Guid Id { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual string LastName { get; set; } 
      public virtual double AverageRating { get; set; } 
      public virtual int Points { get; set; } 
      public virtual bool HasGoldStatus { get; set; } 
		
      public virtual DateTime MemberSince { get; set; } 
      public virtual CustomerCreditRating CreditRating { get; set; } 
      public virtual Location Address { get; set; }
      public virtual ISet<Order> Orders { get; set; }
      public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
      
      public override string ToString() { 
         var result = new StringBuilder(); 
			
         result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
            {4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
            {8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
            CreditRating, MemberSince.Kind, AverageRating);
         result.AppendLine("\tOrders:"); 
         
         foreach(var order in Orders) { 
            result.AppendLine("\t\t" + order); 
         } 
			
         return result.ToString(); 
      } 
   }
   
   public class Location { 
      public virtual string Street { get; set; } 
      public virtual string City { get; set; } 
      public virtual string Province { get; set; } 
      public virtual string Country { get; set; }
   } 
   
   public enum CustomerCreditRating { 
      Excellent, 
      VeryVeryGood, 
      VeryGood, 
      Good, 
      Neutral, 
      Poor, 
      Terrible 
   } 
}

Aqui está o Program.cs implementação de arquivo.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         Guid id; 
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var newCustomer = CreateCustomer(); 
            Console.WriteLine("New Customer:"); 
            Console.WriteLine(newCustomer); 
            session.Save(newCustomer); 
            id = newCustomer.Id;
            tx.Commit(); 
         }
         
         using(var session = sessionFactory.OpenSession())

         using(var tx = session.BeginTransaction()) { 
            var query = from customer in session.Query<Customer>() where
               customer.Id == id select customer; 
					
            var reloaded = query.Fetch(x => x.Orders).ToList().First();
            Console.WriteLine("Reloaded:"); Console.WriteLine(reloaded); 

            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
      
      private static Customer CreateCustomer() { 
         var customer = new Customer { 
            FirstName = "John", 
            LastName = "Doe", 
            Points = 100, 
            HasGoldStatus = true, 
            MemberSince = new DateTime(2012, 1, 1), 
            CreditRating = CustomerCreditRating.Good, 
            AverageRating = 42.42424242, 
            Address = CreateLocation() 
         }; 
			
         var order1 = new Order { Ordered = DateTime.Now }; 
         
         customer.AddOrder(order1); var order2 = new Order {
            Ordered = DateTime.Now.AddDays(-1), 
            Shipped = DateTime.Now, 
            ShipTo = CreateLocation()
         }; 
			
         customer.AddOrder(order2); 
         return customer; 
      }
      
      private static Location CreateLocation() { 
         return new Location { 
            Street = "123 Somewhere Avenue", 
            City = "Nowhere", 
            Province = "Alberta", 
            Country = "Canada" 
         }; 
      }
      
      private static Configuration ConfigureNHibernate() { 
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Ele vai salvar isso no banco de dados e, em seguida, recarregá-lo. Agora vamos executar seu aplicativo e abrir o NHibernate Profiler e ver como ele realmente o salvou.

Você notará que temos 3 grupos de declarações. O primeiro irá inserir o cliente, e o ID desse cliente é o Guid, que está destacado. A segunda instrução é inserida na tabela de pedidos.

Você notará que o mesmo Guia de Id do Cliente está definido lá, então tenha essa chave estrangeira definida. A última instrução é a atualização, que atualizará a chave estrangeira para o mesmo ID do cliente mais uma vez.

Agora o problema é que o cliente tem os pedidos, e os pedidos têm o cliente, não há como não termos dito ao NHibernate que na verdade é o mesmo relacionamento. A maneira como fazemos isso é com inverso igual a verdadeiro.

Então, vamos para o nosso customer.hbm.xml arquivo de mapeamento e defina o inverso igual a verdadeiro, conforme mostrado no código a seguir.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
   
   <class name = "Customer">
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
      
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/>
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan" 
         inverse = "true"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Ao salvar os pedidos, ele definirá essa chave estrangeira do lado do pedido. Agora vamos executar este aplicativo novamente e abrir o perfilador NHibernate.

Se olharmos como eles são inseridos, obtemos a inserção no cliente e a inserção nos pedidos, mas não temos aquela atualização duplicada da chave estrangeira porque ela está sendo atualizada quando os pedidos estão sendo salvos.

  • Agora, você deve notar que se você tem apenas uma associação unidirecional e é o conjunto que está mantendo essa relação, então se você transformar o inverso em verdadeiro, essa chave estrangeira nunca será definida e esses itens nunca terão seus chaves estrangeiras definidas no banco de dados.

  • Se você olhar para o relacionamento muitos para um no Order.hbm.xml arquivo e você procura inverse, na verdade não tem um atributo inverse.

  • Ele sempre é definido a partir do item filho, mas se você tiver uma coleção muitos para muitos, poderá defini-la de qualquer lado.

Neste capítulo, abordaremos como os recursos Carregar e Obter estão funcionando e como podemos usá-los. Estas são duas APIs muito semelhantes fornecidas porISession para carregar um objeto por chave primária.

  • Get - ele retornará o objeto ou um nulo.

  • Load - retornará o objeto ou lançará um ObjectNotFoundException.

Agora, por que temos essas duas APIs diferentes?

Carga

  • É porque o Load pode otimizar as viagens de ida e volta do banco de dados com muito mais eficiência.

  • O carregamento, na verdade, retorna um objeto proxy e não precisa acessar o banco de dados ao emitir a chamada de carregamento.

  • Quando você acessa esse proxy, o objeto não está no banco de dados, ele pode lançar uma ObjectNotFoundException naquele ponto.

Pegue

  • Por outro lado, com Get devido às limitações do CLR ou Common Language Runtime e o NHibernate deve ir ao banco de dados imediatamente, verificar se os objetos estão lá e retornar nulo, se não estiver presente.

  • Ele não tem a opção do objeto de atrasar essa busca, aquela viagem de ida e volta ao banco de dados para um momento posterior, porque não pode retornar um objeto proxy e que trocou esse objeto proxy por um nulo, quando o usuário realmente o acessa.

Vamos dar uma olhada em um exemplo simples no qual você verá como eles são realmente usados ​​e a diferença entre Get e Load. Continuaremos com as mesmas classes de domínioCustomers e Orders e da mesma forma os mesmos arquivos de mapeamento do último capítulo.

Neste exemplo, primeiro usaremos Get conforme mostrado no programa a seguir.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver;
using NHibernate.Linq; 

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be"); 
            var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
				
            var customer1 = session.Get<Customer>(id1); 
            Console.WriteLine("Customer1 data"); 
            Console.WriteLine(customer1);
				
            var customer2 = session.Get<Customer>(id2); 
            Console.WriteLine("Customer2 data"); 
            Console.WriteLine(customer2); 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead;
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Como você pode ver, temos dois GuidIDs, o primeiro é um bom ID, é o ID de um cliente que sabemos que está no banco de dados. Enquanto o segundo ID não está presente no banco de dados. Ambos os IDs são passados ​​como um parâmetro paraGet() método e então o resultado é impresso no console.

Quando o código acima for compilado e executado, você verá a seguinte saída.

Customer1 data
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

Orders:
   Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
   Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
   Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
   Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
	
Customer2 data
Press <ENTER> to exit...

Como você pode ver, os dados do Cliente1 são impressos, mas os dados do Cliente2 estão vazios, isso porque o registro do Cliente2 não está disponível no banco de dados.

Quando você executa seu aplicativo novamente, podemos inserir um ponto de interrupção antes da instrução de confirmação e, em seguida, vamos examinar os dois clientes na janela Watch.

Como você pode ver que os dados do Cliente1 estão disponíveis, enquanto o Cliente2 é nulo e o tipo é NHibernateDemo.Customer para ambos.

Agora vamos usar o método Load em vez de Get no mesmo exemplo mostrado no código a seguir.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver;
using NHibernate.Linq; 

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be"); 
            var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
				
            var customer1 = session.Load<Customer>(id1); 
            Console.WriteLine("Customer1 data"); 
            Console.WriteLine(customer1);
				
            var customer2 = session.Load<Customer>(id2); 
            Console.WriteLine("Customer2 data"); 
            Console.WriteLine(customer2); 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10;
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Agora vamos rodar este exemplo e você verá que a seguinte exceção é lançada como visto na imagem.

Agora, se você olhar a janela Watch, verá que o tipo é proxy do cliente para ambos os objetos. E você também vê os mesmos dados para Customer1 na janela do console.

Customer1 data
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be 
		
Customer2 data

Neste capítulo, iremos cobrir outra API comum que as pessoas usarão é o provedor NHibernate LINQ. Seu acesso através de um método de extensão no ISession e a assinatura é umQuery <T>. Existem dois tipos de sintaxe ao usar LINQ -

  • Sintaxe de encadeamento de consulta
  • Sintaxe de compreensão de consulta

Sintaxe de encadeamento de consulta

Você pode acessar qualquer registro do banco de dados usando a sintaxe da cadeia de método, conforme mostrado no programa a seguir.

var customer = session.Query<Customer>() .Where(c => c.FirstName == "Laverne")
  • Você pode ver que temos consulta, e também a cláusula WHERE, você pode ter cláusulas WHERE adicionais e cláusula de seleção da mesma forma.

  • Esta é uma sintaxe de cadeia de método padrão que você pode usar no LINQ normal.

  • LINQ to Objects ou LINQ to SQL, qualquer um dos outros provedores LINQ com os quais você possa estar familiarizado.

Vamos dar uma olhada em um exemplo simples no qual recuperaremos o cliente cujo primeiro nome é Laverne. Agora é uma possibilidade que possamos ter mais de um cliente cujo primeiro nome é Laverne, portanto, vamos recuperar apenas o primeiro.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program {
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customer = session.Query<Customer>() 
               .Where(c => c.FirstName == "Laverne").First(); 
            Console.WriteLine(customer); 
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Agora, quando o código acima for compilado e executado, você verá a seguinte saída.

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

Sintaxe de compreensão de consulta

Há também a sintaxe de compreensão de consulta, que se parece muito mais com SQL usando as palavras-chave from, where e select.

Portanto, vamos dar uma olhada no mesmo exemplo, mas desta vez usamos a sintaxe de compreensão do LINQ, que se parece muito mais com SQL, conforme mostrado no programa a seguir.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customer = (from c in session.Query<Customer>() 
               where c.FirstName == "Laverne" select c).First();
            Console.WriteLine(customer); 
            tx.Commit();
         }
         
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
      
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Agora vamos executar este aplicativo novamente e você verá a seguinte saída.

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

Vamos dar uma olhada em outro exemplo em que recuperaremos todos esses clientes, cujo FirstName começa com a letra H.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customers = session.Query<Customer>() .Where(c =<
               c.FirstName.StartsWith("H"));
            
            foreach (var customer in customers.ToList()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Da mesma forma, a sintaxe de compreensão da consulta será semelhante ao programa a seguir.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            var customers = from c in session.Query<Customer>() 
               where c.FirstName.StartsWith("H") select c;
            
            foreach (var customer in customers.ToList()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   }  
}

Vamos executar este aplicativo novamente e você verá todos os clientes, cujo nome começa com o alfabeto H.

Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 12/3/2010 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be

Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
   Points: 56
   HasGoldStatus: False
   MemberSince: 10/20/2008 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be

Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
   Points: 82
   HasGoldStatus: False
   MemberSince: 4/10/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
		
Press <ENTER> to exit...

Neste capítulo, abordaremos a linguagem de consulta do Hibernate. O HQL é compartilhado entre o Hibernate e o NHibernate do Java.

  • É o mecanismo de consulta mais antigo junto com Criteria.

  • Foi implementado muito cedo e é uma consulta baseada em string API.

  • Você acessa através de ISession CreateQuerye é quase semelhante ao SQL.

  • Ele usa muitas das mesmas palavras-chave, mas tem uma sintaxe simplificada.

  • É um dos exemplos mais comuns, se você está procurando como realizar uma consulta, frequentemente encontrará exemplos de HQL.

A seguir está um exemplo simples de HQL -

var customers = session.CreateQuery("select c from Customer c where c.FirstName = 'Laverne'");
  • Então, aqui você pode ver que eles selecionam C do cliente, parece muito com SQL. Esta é uma string opaca no que diz respeito ao NHibernate, então você não sabe se este é um HQL válido até o tempo de execução, o que é uma das desvantagens.

  • Um dos pontos fortes do provedor LINQ é que você pode obter suporte em tempo de compilação.

  • Mas HQL é um dos mecanismos de consulta mais flexíveis frequentemente usados. Diz-se que, se não há outra maneira de fazer, então há uma maneira de fazer em HQL.

Vamos dar uma olhada em um exemplo simpe em que recriaremos nossas consultas LINQ usando HQL. Você pode obter acesso ao HQL chamando osession.CreateQuery e passar como um parâmetro usando uma string HQL.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo {

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateQuery("select c from Customer c 
               where c.FirstName = 'Laverne'"); 
            
            foreach (var customer in customers.List<Customer>()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}
  • Esta string HQL se parece muito com SQL, a principal diferença é que FirstName é o nome da propriedade e não o nome da coluna.

  • Portanto, se houver uma discrepância entre os dois, use o nome da propriedade. Mesma coisa, parece um nome de tabela, mas na verdade é o nome da classe da qual estamos selecionando.

  • Se a tabela de back end fosse nomeada como Clientes, ainda usaríamos Cliente em nossa consulta HQL.

Vamos executar este aplicativo e você verá a seguinte saída.

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

Vamos dar uma olhada em outro exemplo simples no qual recuperaremos todos os clientes cujo FirstName começa com a letra H usando HQL.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver;
using NHibernate.Linq; 

namespace NHibernateDemo { 

   internal class Program {
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateQuery("select c from Customer c 
               where c.FirstName like 'H%'"); 
            
            foreach (var customer in customers.List<Customer>()) { 
               Console.WriteLine(customer); 
            }
				
            tx.Commit(); 
         } 
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      } 
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Vamos executar seu aplicativo novamente e você verá que todos os clientes cujos nomes começam com H são retornados desta consulta.

Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 12/3/2010 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be

Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
   Points: 56
   HasGoldStatus: False
   MemberSince: 10/20/2008 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be

Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
   Points: 82
   HasGoldStatus: False
   MemberSince: 4/10/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
		
Press <ENTER> to exit...

Podemos fazer coisas mais complicadas, como desejar todos os pedidos em que os clientes com uma contagem de pedidos sejam maiores que 9. A seguir está a consulta HQL para o mesmo.

var customers = session.CreateQuery("select c from Customer c 
   where size(c.Orders) > 9"); 
	
foreach (var customer in customers.List<Customer>()) { 
   Console.WriteLine(customer); 
}

Também precisamos indicar que precisamos de um tamanho aqui ou contagem ou comprimento. Em HQL, temos a opção de usar o método de tamanho especial conforme mostrado acima.

A outra maneira de escrever isso, se você preferir, é c.Orders.size, e isso tem o efeito exato.

var customers = session.CreateQuery("select c from Customer c 
   where c.Orders.size > 9"); 
	
foreach (var customer in customers.List<Customer>()) { 
   Console.WriteLine(customer); 
}

Vamos rodar este aplicativo.

Lindsay Towne (4ea3aef6-6bce-11e1-b0cb-6cf049ee52be)
   Points: 50
   HasGoldStatus: False
   MemberSince: 4/13/2007 12:00:00 AM (Utc)
   CreditRating: VeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ea3aef6-6bce-11e1-b0cc-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0cd-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0ce-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0cf-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d0-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d1-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d2-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d3-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d4-6cf049ee52be
      Order Id: 4ea3aef6-6bce-11e1-b0d5-6cf049ee52be

Wyman Hammes (4ea61056-6bce-11e1-b0e2-6cf049ee52be)
   Points: 32
   HasGoldStatus: False
   MemberSince: 2/5/2011 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 0

   Orders:
      Order Id: 4ea61056-6bce-11e1-b0e3-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e4-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e5-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e6-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e7-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e8-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0e9-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0ea-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0eb-6cf049ee52be
      Order Id: 4ea61056-6bce-11e1-b0ec-6cf049ee52be
		
Press <ENTER> to exit...

Você pode ver que todos os clientes, que têm mais de 9 pedidos, são recuperados do banco de dados.

Neste capítulo, iremos cobrir o mecanismo de consultas de critérios. oNHibernate Query by Criteria API permite criar uma consulta manipulando objetos de critérios em tempo de execução.

  • Essa abordagem permite especificar restrições dinamicamente sem manipulações diretas de string, mas não perde muito da flexibilidade ou poder do HQL.

  • Por outro lado, as consultas expressas como critérios costumam ser menos legíveis do que as consultas expressas em HQL.

  • A sintaxe de critérios clássicos é uma API de consulta baseada em objeto, conforme mostrado no programa a seguir.

var customers = session.CreateCriteria<Customer>().Add(Restrictions.Like("FirstName", "H%"));
  • Como você pode ver, estamos criando um critério de criação de sessão no cliente e agora estamos adicionando um objeto de restrição a essa consulta.

  • Isso é útil para páginas de consulta onde os usuários podem selecionar certas opções, mas não outras.

  • É mais fácil construir a consulta como uma espécie de árvore como a estrutura da consulta, em vez de em HQL ou LINQ, onde você pode usar AND ou OR na cláusula WHERE.

  • É mais fácil simplesmente adicionar restrições adicionais usando esses objetos de critérios.

Vamos dar uma olhada em um exemplo simples em que criaremos uma consulta e obteremos acesso à API de critérios por meio createCriteria e adicione uma restrição de que o primeiro nome comece com H.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq; 

namespace NHibernateDemo {

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateCriteria<Customer>() 
               .Add(Restrictions.Like("FirstName", "H%")); 
         
            foreach (var customer in customers.List<Customer>()) { 
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      } 
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Quando o código acima for compilado e executado, você verá a seguinte saída.

Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 12/3/2010 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
      Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be

Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
   Points: 56
   HasGoldStatus: False
   MemberSince: 10/20/2008 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
      Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be

Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
   Points: 82
   HasGoldStatus: False
   MemberSince: 4/10/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
      Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
		
Press <ENTER> to exit…

Vamos dar uma olhada em outro exemplo simples em que recuperaremos o cliente cujo nome é igual a "Laverne"

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) { 
            var customers = session.CreateCriteria<Customer>() 
               .Add(Restrictions.Eq("FirstName", "Laverne")) .List<Customer>(); 
            
            foreach (var customer in customers) {
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() {
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Vamos executar este aplicativo novamente e você verá a seguinte saída.

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

Agora, uma das principais desvantagens da API de critérios são essas strings opacas nos nomes das propriedades. Portanto, se o primeiro nome fosse refatorado para ser outra coisa, a ferramenta de refatoração não necessariamente pegaria a string opaca.

Neste capítulo, iremos cobrir as consultas QueryOver. É uma nova sintaxe que se parece mais com LINQ usando a sintaxe de cadeia de método, conforme mostrado na consulta a seguir.

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "Laverne");
  • Ainda são critérios ocultos, mas agora nossas consultas são fortemente tipadas.

  • Como vimos na consulta de critérios, o primeiro nome é apenas uma string opaca, agora estamos realmente usando um x.FirstName, portanto, o primeiro nome é refatorado e renomeado, sendo alterado na consulta de critérios de estilo de link usando a consulta over.

  • Ainda podemos fazer muitas coisas semelhantes, mas você não pode usar a sintaxe de compreensão de consulta com a consulta over, você tem que usar a sintaxe de cadeia de método e não pode misturar e combinar o link e os critérios.

  • Para muitas consultas, a consulta sobre API é muito útil e fornece uma compreensão muito mais fácil da sintaxe do objeto do que usar Critérios diretamente.

Vamos dar uma olhada em um exemplo simples no qual recuperaremos um cliente cujo primeiro nome é Laverne usando uma consulta over.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
      
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) { 
            var customers = session.QueryOver<Customer>() 
               .Where(x => x.FirstName == "Laverne"); 
            
            foreach (var customer in customers.List()) { 
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
      
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize();
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         });
			
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Como você pode ver, ainda é Critérios por baixo dos panos, mas é apenas uma sintaxe mais agradável.

Quando o código acima for compilado e executado, você verá a seguinte saída.

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

Uma das desvantagens é que, digamos que queremos dizer que FirstName.StartsWith(“A”) conforme mostrado no programa a seguir.

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName.StartsWith("A"));
 
foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
} 

tx.Commit();

Agora vamos executar o aplicativo novamente e você verá que este não é um provedor LINQ, pois não sabe o que é StartsWith método é, então você obterá um RunTime exception.

A exceção diz chamada de método não reconhecida. Aqui estamos fazendo o óbvio, mas não necessariamente funciona.

Vamos tentar outra coisa, como o FirstName é igual a “A%” conforme mostrado no código a seguir.

var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "A%"); 

foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
}

Vamos executar isso mais uma vez e você verá que não obteremos nenhum resultado como mostrado abaixo.

Press <ENTER> to exit...

Para entender por que não estamos obtendo nenhum resultado, vamos dar uma olhada no perfilador do NHibernate.

Como você pode ver que o primeiro nome é igual a A% que não é. Um% é usado em SQL com o operador like. Agora precisamos criar uma restrição na cláusula WHERE, conforme mostrado no programa a seguir.

var customers = session.QueryOver<Customer>() 
   .Where(Restrictions.On<Customer>(c => c.FirstName).IsLike("A%")); 
	
foreach (var customer in customers.List()) { 
   Console.WriteLine(customer); 
}

Vamos executar seu aplicativo novamente e você verá que todos os clientes são recuperados com o primeiro nome começando com A.

Alejandrin Will (4ea3aef6-6bce-11e1-b0b4-6cf049ee52be)
   Points: 24
   HasGoldStatus: False
   MemberSince: 10/1/2011 12:00:00 AM (Utc)
   CreditRating: VeryVeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ea3aef6-6bce-11e1-b0b5-6cf049ee52be

Austyn Nolan (4ea871b6-6bce-11e1-b110-6cf049ee52be)
   Points: 67
   HasGoldStatus: True
   MemberSince: 12/29/2007 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea871b6-6bce-11e1-b111-6cf049ee52be

Antonia Murphy (4ea871b6-6bce-11e1-b121-6cf049ee52be)
   Points: 72
   HasGoldStatus: True
   MemberSince: 6/15/2009 12:00:00 AM (Utc)
   CreditRating: Terrible
   AverageRating: 0

   Orders:
      Order Id: 4ea871b6-6bce-11e1-b122-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b123-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b124-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b125-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b126-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b127-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b128-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b129-6cf049ee52be
      Order Id: 4ea871b6-6bce-11e1-b12a-6cf049ee52be

Funciona da mesma forma que antes, exceto pelo uso deste novo QueryOversintaxe. Muitos desenvolvedores acham que a sintaxe do LINQ é mais acessível e geralmente faz as coisas certas.

Se o LINQ não puder lidar com isso, você começará a examinar o HQL ou os critérios para ver se isso será mais adequado.

Ele apenas fornece uma sintaxe diferente, então Criteria, ambos os critérios de criação e o QueryOver fornecem a você apenas mais um mecanismo de consulta que permite a você extrair dados do banco de dados usando NHibernate.

Neste capítulo, iremos cobrir como usar as consultas SQL nativas no NHibernate. Se você já usa SQL manuscrito há vários anos, pode estar preocupado com o fato de o ORM tirar um pouco da expressividade e flexibilidade a que está acostumado.

  • Os recursos de consulta poderosos do NHibernate permitem que você faça quase tudo que você faria no SQL e, em alguns casos, mais.

  • Para os raros casos em que você não pode fazer os próprios recursos de consulta do NHibernate fazerem exatamente o que você deseja.

  • NHibernate permite que você recupere objetos usando o dialeto SQL nativo do seu banco de dados.

Vamos dar uma olhada em um exemplo simples de consultas SQL nativas no NHibernate.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Criterion; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq; 
using NHibernate;

namespace NHibernateDemo {

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         using(var session = sessionFactory.OpenSession()) 
         
         using(var tx = session.BeginTransaction()) {
            IQuery sqlQuery = session.CreateSQLQuery("SELECT * FROM
               CUSTOMER").AddEntity(typeof(Customer));
            var customers = sqlQuery.List<Customer>();
				
            foreach (var customer in customers) { 
               Console.WriteLine(customer); 
            } 
				
            tx.Commit(); 
         }
         
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect>(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10; 
            x.BatchSize = 10; 
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

O exemplo acima usa CreateSQLQuery() para obter uma lista de objetos, e você também notará que o tipo de entidade raiz que você deseja que a consulta retorne é especificado como Cliente.

Vamos rodar seu aplicativo e você verá que todos os clientes foram recuperados do banco de dados.

Emerson Prosacco (4ec2a0e0-6bce-11e1-b2cf-6cf049ee52be)
   Points: 17
   HasGoldStatus: False
   MemberSince: 6/22/2007 12:00:00 AM (Utc)
   CreditRating: Excellent
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2d0-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d1-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d2-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d3-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d4-6cf049ee52be

Kaci Friesen (4ec2a0e0-6bce-11e1-b2d5-6cf049ee52be)
   Points: 30
   HasGoldStatus: True
   MemberSince: 5/25/2007 12:00:00 AM (Utc)
   CreditRating: VeryVeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2d6-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d7-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d8-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2d9-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2da-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2db-6cf049ee52be

Eveline Waters (4ec2a0e0-6bce-11e1-b2dc-6cf049ee52be)
   Points: 58
   HasGoldStatus: False
   MemberSince: 10/29/2009 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2dd-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2de-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2df-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e0-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e2-6cf049ee52be

Molly Kuhn (4ec2a0e0-6bce-11e1-b2e3-6cf049ee52be)
   Points: 73
   HasGoldStatus: False
   MemberSince: 12/16/2007 12:00:00 AM (Utc)
   CreditRating: VeryGood
   AverageRating: 0

   Orders:
      Order Id: 4ec2a0e0-6bce-11e1-b2e4-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e5-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e6-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e7-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e8-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2e9-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2ea-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2eb-6cf049ee52be
      Order Id: 4ec2a0e0-6bce-11e1-b2ec-6cf049ee52be

Aqui está outra maneira de escrever uma consulta SQL nativa, conforme mostrado abaixo.

IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER")
   .AddScalar("Id", NHibernateUtil.Guid) 
   .AddScalar("FirstName", NHibernateUtil.String) 
   .AddScalar("LastName", NHibernateUtil.String) .List<Customer>();
  • Como você pode ver, a consulta acima especificou a string de consulta SQL e as colunas e tipos a serem retornados.

  • Isso retornará uma IList of Object arrays com valores escalares para cada coluna na tabela Customer.

  • Apenas essas três colunas serão retornadas, embora a consulta esteja usando * e possa retornar mais do que as três colunas listadas.

Vamos dar uma olhada em outro exemplo simples.

IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER WHERE  
   FirstName = 'Laverne'") 
   .AddEntity(typeof(Customer)) .List<Customer>(); 
	
foreach (var customer in customers) { 
   Console.WriteLine(customer); 
}

Vamos executar seu aplicativo novamente e você verá a seguinte saída.

Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
   Points: 74
   HasGoldStatus: True
   MemberSince: 4/4/2009 12:00:00 AM (Utc)
   CreditRating: Neutral
   AverageRating: 0

   Orders:
      Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
      Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
		
Press <ENTER> to exit...

Da mesma forma, você pode especificar qualquer tipo de consulta SQL para recuperar dados do banco de dados.

Neste capítulo, iremos cobrir o NHibernate fluente. O Fluent NHibernate é outra forma de mapeamento ou você pode dizer que é uma alternativa aos arquivos de mapeamento XML padrão do NHibernate. Em vez de escrever XML(.hbm.xml files)documentos. Com a ajuda do Fluent NHibernate, você pode escrever mapeamentos em código C # fortemente tipado.

  • No Fluent NHibernate, os mapeamentos são compilados junto com o restante do seu aplicativo.

  • Você pode alterar facilmente seus mapeamentos, assim como o código do aplicativo e o compilador falhará em qualquer erro de digitação.

  • Possui um sistema de configuração convencional, onde você pode especificar padrões para substituir convenções de nomenclatura e muitas outras coisas.

  • Você também pode definir como as coisas devem ser nomeadas uma vez, então o Fluent NHibernate faz o resto.

Vamos dar uma olhada em um exemplo simples criando um novo projeto de console. Neste capítulo, usaremos um banco de dados simples no qual temos uma tabela Cliente simples, conforme mostrado na imagem a seguir.

Instale o Fluent NHibernate

A primeira etapa é iniciar o Fluent NHibernate é instalar o pacote Fluent NHibernate. Então abra oNuGet Package Manager Console e digite o seguinte comando.

PM> install-package FluentNHibernate

Depois de instalado com sucesso, você verá a seguinte mensagem.

Vamos adicionar uma classe de modelo simples de Cliente e o programa a seguir mostra a implementação da classe Cliente.

using System; 
using System.Collections.Generic; 
using System.Linq;
using System.Text; 
using System.Threading.Tasks;

namespace FluentNHibernateDemo { 
   class Customer { 
      public virtual int Id { get; set; } 
      public virtual string FirstName { get; set; } 
      public virtual string LastName { get; set; } 
   } 
}

Agora precisamos criar mapeamentos usando NHibernate fluente, então adicione mais uma classe CustomerMapno seu projecto. Aqui está a implementação da classe CustomerMap.

using FluentNHibernate.Mapping; 
using System; 
using System.Collections.Generic; 
using System.Linq; using System.Text; 
using System.Threading.Tasks;

namespace FluentNHibernateDemo { 
   class CustomerMap : ClassMap<Customer> { 
      public CustomerMap() { 
         Id(x => x.Id); 
         Map(x => x.FirstName); 
         Map(x => x.LastName); 
         Table("Customer"); 
      } 
   }
}

Vamos adicionar outra classe NHibernateHelper em que definiremos diferentes configurações.

using FluentNHibernate.Cfg; 
using FluentNHibernate.Cfg.Db; 
using NHibernate; 
using NHibernate.Tool.hbm2ddl;

namespace FluentNHibernateDemo { 

   public class NHibernateHelper { 
	
      private static ISessionFactory _sessionFactory;
		
      private static ISessionFactory SessionFactory { 
         get { 
            if (_sessionFactory == null)
            InitializeSessionFactory(); return _sessionFactory; 
         } 
      }
   
      private static void InitializeSessionFactory() { 
         _sessionFactory = Fluently.Configure() 
			
         String Data Source = asia13797\\sqlexpress;
         String Initial Catalog = NHibernateDemoDB;
         String Integrated Security = True;
         String Connect Timeout = 15;
         String Encrypt = False;
         String TrustServerCertificate = False;
         String ApplicationIntent = ReadWrite;
         String MultiSubnetFailover = False;
			
         .Database(MsSqlConfiguration.MsSql2008 .ConnectionString( 
            @"Data Source + Initial Catalog + Integrated Security + Connect Timeout
            + Encrypt + TrustServerCertificate + ApplicationIntent + 
            MultiSubnetFailover") .ShowSql() ) 
				
         .Mappings(m => m.FluentMappings
         .AddFromAssemblyOf<Program>()) 
         .ExposeConfiguration(cfg => new SchemaExport(cfg) 
         .Create(true, true)) 
         .BuildSessionFactory(); 
      }
		
      public static ISession OpenSession() { 
         return SessionFactory.OpenSession(); 
      } 
   }
}

Agora vamos passar para o Program.cs arquivo no qual iniciaremos uma sessão e, em seguida, criaremos um novo cliente e salvaremos esse cliente no banco de dados, conforme mostrado abaixo.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks;

namespace FluentNHibernateDemo { 
   class Program { 
	
      static void Main(string[] args) { 
		
         using (var session = NHibernateHelper.OpenSession()) { 
			
            using (var transaction = session.BeginTransaction()) { 
               var customer = new Customer { 
                  FirstName = "Allan", 
                  LastName = "Bomer" 
               }; 
					
               session.Save(customer); 
               transaction.Commit();
               Console.WriteLine("Customer Created: " + customer.FirstName + "\t" +
                  customer.LastName); 
            } 
				
            Console.ReadKey(); 
         } 
      } 
   } 
}

Vamos executar seu aplicativo e você verá a seguinte saída.

if exists (select * from dbo.sysobjects where id = object_id(N'Customer') and
   OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Customer

create table Customer (
   Id INT IDENTITY NOT NULL,
   FirstName NVARCHAR(255) null,
   LastName NVARCHAR(255) null,
   primary key (Id)
)

NHibernate: INSERT INTO Customer (FirstName, LastName) VALUES (@p0, @p1); 
   select SCOPE_IDENTITY();@p0 = 'Allan' [Type: String (4000)], 
   @p1 = 'Bomer' [Type: String (4000)]
   Customer Created: Allan Bomer

Como você pode ver, o novo cliente foi criado. Para ver o registro do cliente, vamos ao banco de dados e ver os dados de exibição e você verá que 1 cliente foi adicionado.