NHibernate - Mapeamento de Tipos de Dados

Neste capítulo, abordaremos os tipos de dados de mapeamento. O mapeamento de entidades é direto, 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 na classe Aluno.

Agora vamos mudar o FirstMidName para FirstName na classe do aluno, onde não mudaremos a coluna FirstMidName, mas veremos como informar 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á listada 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, 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.