NHibernate - Componente di mappatura
In questo capitolo parleremo dei componenti di mappatura. In NHibernate,component is a value object. Non ha un'identità propria.
Un esempio di questo potrebbe essere un oggetto denaro, una borsa o un portafoglio potrebbe contenere denaro, ma l'identità esatta di quel denaro è irrilevante.
Non dispone di una propria chiave primaria, ma i componenti stessi sono persistenti nella stessa tabella dell'oggetto proprietario.
Diamo un'occhiata a un semplice esempio in cui uno studente ha un indirizzo, che è un oggetto di Location class associati ad esso.
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
}
}
Ora, dobbiamo anche aggiornare il database eseguendo la seguente query, che prima eliminerà la tabella Student e quindi creerà una nuova tabella che conterrà anche una colonna per la classe Location.
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)
);
Ora per mappare quelle colonne che non fanno parte direttamente della classe Student, ma sono proprietà della classe Location e l'oggetto della classe Location è definito nella classe student. Abbiamo bisogno di un componente per mapparlo correttamente. Creiamo un componente instudent.hbm.xml file come mostrato nel codice seguente.
<?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>
Questo componente è l'indirizzo e ha queste diverse proprietà su di esso. Con queste informazioni, NHibernate ora ha abbastanza per poterlo mappare effettivamente.
Ora ecco il file Program.cs in cui viene creato e inizializzato un nuovo oggetto studente e quindi salvato nel database. Quindi recupererà l'elenco dal database.
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();
}
}
}
}
Ora possiamo eseguire questa applicazione e NHibernate può salvare quei valori nel database. Quando esegui l'applicazione, vedrai il seguente output.
Fetch the complete list again
2 Allan Bommer Poor 123 Street Lahore Punjab Pakistan
Ecco i valori nel database.
I componenti ci consentono di separare le colonne che si trovano in una tabella di database nella loro classe separata.
L'altra cosa da notare qui è perché Location è una classe, non è un'entità.
È un oggetto di tipo valore e non ha una propria chiave primaria.
Viene salvato nella stessa tabella dello Studente che lo contiene.
Ecco perché stiamo usando il componente qui.
Ciò consente molta flessibilità per cambiare il nostro livello di classe, come sono definite le nostre classi rispetto a come è strutturato il nostro database.