NHibernate - Mapowanie typów danych

W tym rozdziale zajmiemy się mapowaniem typów danych. Mapowanie jednostek jest proste, klasy jednostek są zawsze mapowane na tabele bazy danych przy użyciu<class>, <subclass>, and <joined-subclass>mapowanie elementów. Typy wartości potrzebują czegoś więcej, czyli tam, gdzie są wymagane typy mapowania.

NHibernate jest w stanie mapować szeroką gamę typów danych. Oto lista najczęściej obsługiwanych typów danych.

Typ mapowania Typ .NET System.Data.DbType
Int16 System.Int16 DbType.Int16
Int32 System.Int32 DbType.Int32
Int64 System.Int64 DbType.Int64
Pojedynczy System.Single DbType.Single
Podwójnie System.Double DbType.Double
Dziesiętny System.Decimal DbType.Decimal
Strunowy System.String DbType.String
AnsiString System.String DbType.AnsiString
Bajt System.Byte DbType.Byte
Zwęglać System.Char DbType.StringFixedLength - jeden znak
AnsiChar System.Char DbType.AnsiStringFixedLength - jeden znak
Boolean System.Boolean DbType.Boolean
Guid System.Guid DbType.Guid
PersistentEnum System.Enum (wyliczenie) DbType dla wartości bazowej
Prawda fałsz System.Boolean DbType.AnsiStringFixedLength - „T” lub „F”
Tak nie System.Boolean DbType.AnsiStringFixedLength - „Y” lub „N”
DateTime DateTime DbType.DateTime - ignoruje milisekundy
Kleszcze System.DateTime DbType.Int64
Okres czasu System.TimeSpan DbType.Int64
Znak czasu System.DateTime DbType.DateTime - tak specyficzne, jak obsługuje baza danych
Dwójkowy System.Byte [] DbType.Binary
BinaryBlob System.Byte [] DbType.Binary
StringClob System.String DbType.String
Możliwość serializacji Dowolny System.Object oznaczony SerializableAttribute DbType.Binary
CultureInfo System.Globalization.CultureInfo DbType.String - pięć znaków dla kultury
Rodzaj Rodzaj systemu DbType.String przechowujący kwalifikowaną nazwę zespołu

Powyższa tabela szczegółowo wyjaśnia poniższe wskazówki.

  • Wszystko, od prostych typów liczbowych po ciągi, które można odwzorowywać na różne sposoby przy użyciu varchars, chars itp., a także ciągowe obiekty blob i wszelkiego rodzaju typy obsługiwane przez bazy danych.

  • Jest również w stanie mapować Booleans, zarówno do pól z zerami i jedynkami, pól znakowych zawierających wartość true, false lub T i F.

  • Istnieje wiele różnych sposobów definiowania tego, w jaki sposób odwzorowuje się to na zaplecze, wartości boolowskie w bazie danych.

  • Możemy obsłużyć mapowanie DateTime, włączając i wyłączając przesunięcia stref czasowych, czas letni itp.

  • Możemy również mapować enumerations; możemy odwzorować je na łańcuchy lub na ich podstawowe wartości liczbowe.

Przyjrzyjmy się prostemu przykładowi, w którym mamy te same nazwy właściwości zarówno w bazie danych, jak iw klasie Student.

Teraz zmieńmy FirstMidName na FirstName w klasie ucznia, gdzie nie zmienimy kolumny FirstMidName, ale zobaczymy, jak powiedzieć NHibernate, że ma przeprowadzić tę konwersję. Poniżej znajduje się zaktualizowana klasa uczniów.

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

Oto implementacja pliku mapowania 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>

W tym przykładzie załóżmy, że pole FirstName to ciąg .NET, a kolumna FirstMidName to SQL nvarchar. Teraz, aby powiedzieć NHibernate, jak przeprowadzić tę konwersję, ustaw nazwę na równąFirstName i kolumna równa FirstMidName i określ typ odwzorowania równy String, który jest odpowiedni dla tej konkretnej konwersji.

Poniżej znajduje się plik Program.cs implementacja plików.

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

Teraz po uruchomieniu aplikacji zobaczysz następujące dane wyjściowe.

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

Jak widać, zamapował inną nazwę właściwości na nazwę kolumny w bazie danych.

Spójrzmy na inny przykład, w którym dodamy kolejną właściwość w klasie Student enumrodzaj. Oto implementacja klasy 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 
   } 
}

Jak widać, wyliczenie ma wiele różnych wartości, które może mieć, takie jak: Doskonała, Dobra, Dostateczna, Słaba i Okropna.

Przechodząc do pliku mapowania, można zauważyć, że każda z tych właściwości jest wymieniona w pliku mapowania, w tym nowo dodana AcademicStanding własność.

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

Teraz musimy również zmienić bazę danych, więc przejdź do Eksploratora obiektów SQL Server i kliknij bazę danych prawym przyciskiem myszy i wybierz opcję Nowa kwerenda….

Otworzy edytor zapytań, a następnie określi poniższe zapytanie.

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

To zapytanie najpierw usunie istniejącą tabelę uczniów, a następnie utworzy nową tabelę.

Kliknij ikonę Wykonaj, jak pokazano powyżej. Po pomyślnym wykonaniu zapytania pojawi się komunikat.

Rozwiń bazę danych i listę rozwijaną Tabela, a następnie kliknij prawym przyciskiem myszy tabelę Ucznia i wybierz Projektanta widoku.

Teraz zobaczysz nowo utworzoną tabelę, która ma również nową właściwość AcademicStanding.

Dodajmy dwa rekordy, jak pokazano poniżej Program.cs plik.

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

Teraz uruchommy twoją aplikację, a zobaczysz następujące dane wyjściowe w oknie konsoli.

Fetch the complete list again

1 Allan Bommer Excellent
2 Jerry Lewis Good

Teraz spójrzmy do bazy danych, klikając prawym przyciskiem myszy tabelę uczniów.

Wybierz opcję Wyświetl dane, a zobaczysz dwa rekordy w tabeli uczniów, jak pokazano na poniższym zrzucie ekranu.

Możesz zobaczyć, że dodano dwa rekordy, a Allan ma AcademicStanding 0, a Jerry ma AcademicStanding 1. Dzieje się tak, ponieważ w .Net pierwsza wartość wyliczenia domyślnie ma 0, co oznacza, że StudentAcademicStanding. Natomiast w pliku Student.cs Good jest drugim, więc ma wartość 1.