NHibernate - Mapeo de tipos de datos

En este capítulo, cubriremos los tipos de datos de mapeo. La asignación de entidades es sencilla, las clases de entidad siempre se asignan a las tablas de la base de datos mediante<class>, <subclass>, and <joined-subclass>elementos de mapeo. Los tipos de valor necesitan algo más, que es donde se requieren los tipos de mapeo.

NHibernate puede mapear una amplia variedad de tipos de datos. Aquí está la lista de los tipos de datos más comunes que son compatibles.

Tipo de mapeo Tipo .NET System.Data.DbType
Int16 System.Int16 DbType.Int16
Int32 System.Int32 DbType.Int32
Int64 System.Int64 DbType.Int64
Soltero System.Single DbType.Single
Doble Sistema.Double DbType.Double
Decimal System.Decimal DbType.Decimal
Cuerda System.String DbType.String
AnsiString System.String DbType.AnsiString
Byte System.Byte DbType.Byte
Carbonizarse System.Char DbType.StringFixedLength: un carácter
AnsiChar System.Char DbType.AnsiStringFixedLength: un carácter
Booleano System.Boolean DbType.Boolean
Guid System.Guid DbType.Guid
PersistentEnum System.Enum (una enumeración) DbType para el valor subyacente
Verdadero Falso System.Boolean DbType.AnsiStringFixedLength: 'T' o 'F'
Sí No System.Boolean DbType.AnsiStringFixedLength: 'Y' o 'N'
Fecha y hora Fecha y hora DbType.DateTime: ignora milisegundos
Garrapatas System.DateTime DbType.Int64
Espacio de tiempo System.TimeSpan DbType.Int64
Marca de tiempo System.DateTime DbType.DateTime: tan específico como la base de datos admita
Binario System.Byte [] DbType.Binary
BinaryBlob System.Byte [] DbType.Binary
StringClob System.String DbType.String
Serializable Cualquier System.Object marcado con SerializableAttribute DbType.Binary
CultureInfo System.Globalization.CultureInfo DbType.String: cinco caracteres para referencia cultural
Tipo Tipo de sistema DbType.String que contiene el nombre calificado de ensamblado

La tabla proporcionada anteriormente explica en detalle los indicadores mencionados a continuación.

  • Todo, desde simples tipos numéricos hasta cadenas, que se pueden asignar de diversas formas mediante varchars, chars etc., así como blobs de cadenas y toda la variedad de tipos que admiten las bases de datos.

  • También es capaz de mapear Booleans, tanto para campos que usan ceros como unos, campos de caracteres que contienen verdadero, falso o T y F.

  • Hay una amplia variedad de formas de definir cómo se asigna al back-end, los valores booleanos en la base de datos.

  • Podemos manejar el mapeo de DateTime, que incluyen y excluyen las compensaciones de zona horaria, el horario de verano, etc.

  • También podemos mapear enumerations; podemos asignarlos a cadenas o sus valores numéricos subyacentes.

Echemos un vistazo a un ejemplo simple en el que tenemos los mismos nombres de propiedad tanto en la base de datos como en la clase Student.

Ahora cambiemos FirstMidName a FirstName en la clase del estudiante, donde no cambiaremos la columna FirstMidName, pero veremos cómo decirle a NHibernate que sepa realizar esta conversión. A continuación se muestra la clase de estudiantes actualizada.

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; } 
   }
}

Aquí está la implementación del archivo de mapeo 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>

En este ejemplo, suponga que el campo FirstName es una cadena .NET y la columna FirstMidName es una SQL nvarchar. Ahora, para decirle a NHibernate cómo realizar esta conversión, establezca el nombre igual aFirstName y columna igual a FirstMidName y especifique el tipo de mapeo igual a String, que es apropiado para esta conversión en particular.

La siguiente es una Program.cs implementación de archivos.

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(); 
         } 
      } 
   }
}

Ahora, cuando ejecute su aplicación, verá el siguiente resultado.

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 puede ver, ha asignado el nombre de la propiedad diferente al nombre de la columna en la base de datos.

Echemos un vistazo a otro ejemplo en el que agregaremos otra propiedad en la clase Student de enumtipo. Aquí está la implementación de la clase Student.

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 puede ver, la enumeración tiene una variedad de valores diferentes que posiblemente pueda tener, como Excelente, Bueno, Regular, Deficiente y Terrible.

Saltando al archivo de mapeo, puede ver que cada una de estas propiedades se enumeran en el archivo de mapeo, incluido el recién agregado AcademicStanding propiedad.

<?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>

Ahora también necesitamos cambiar la base de datos, así que vaya al Explorador de objetos de SQL Server, haga clic con el botón derecho en la base de datos y seleccione la opción Nueva consulta ...

Abrirá el editor de consultas y luego especificará la siguiente consulta.

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 primero eliminará la tabla de estudiantes existente y luego creará una nueva tabla.

Haga clic en el icono Ejecutar como se muestra arriba. Una vez que la consulta se ejecuta con éxito, verá un mensaje.

Expanda el menú desplegable de la base de datos y la tabla, y luego haga clic con el botón derecho en la tabla de estudiantes y seleccione Ver diseñador.

Ahora, verá la tabla recién creada, que también tiene la nueva propiedad AcademicStanding.

Agreguemos dos registros como se muestra a continuación. Program.cs archivo.

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(); 
         } 
      } 
   } 
}

Ahora ejecutemos su aplicación y verá el siguiente resultado en la ventana de su consola.

Fetch the complete list again

1 Allan Bommer Excellent
2 Jerry Lewis Good

Ahora echemos un vistazo a la base de datos haciendo clic con el botón derecho en la tabla de estudiantes.

Seleccione Ver datos y verá los dos registros en la tabla de estudiantes como se muestra en la siguiente captura de pantalla.

Puede ver que se agregan dos registros y Allan tiene AcademicStanding 0 y Jerry tiene AcademicStanding 1. Esto se debe a que en .Net el primer valor de enumeración predeterminado tiene 0, que es Excelente si miras StudentAcademicStanding. Mientras que, en el archivo Student.cs, Good es el segundo, por lo que tiene un valor de 1.