在本章中,我们将讨论映射组件.在NHibernate中,组件是一个值对象.它没有自己的身份.
这个例子就是钱币,钱包或者钱币钱包可能有钱,但这笔钱的确切身份是无关紧要的.
它没有自己的主键,但组件本身是持久的与拥有对象在同一个表中.
让我们看一个学生有一个地址的简单例子,与位置等级相关联的对象.
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 } }
现在,我们还需要通过执行以下查询来更新数据库,该查询首先删除Student表,然后创建一个新表,它还将包含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) );
现在映射那些不直接属于Student类的列,但它们是Location类的属性,Location类对象是在student类中定义的.我们需要一个组件来正确映射它.让我们在 student.hbm.xml 文件中创建一个组件,如下面的代码所示.
此组件是地址,它具有这些不同的属性.有了这些信息,NHibernate现在已足够实际映射它了.
现在这里是Program.cs文件,其中创建并初始化一个新的学生对象,然后保存到数据库.然后它将从数据库中检索列表.
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(); x.Dialect (); }); 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 ().ToList (); 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(); } } } }
现在我们可以运行这个应用程序,NHibernate可以保存这些值到数据库.当您运行该应用程序时,您将看到以下输出.
Fetch the complete list again2 Allan Bommer Poor 123 Street Lahore Punjab Pakistan
以下是数据库中的值.
这些组件允许我们将数据库表中的列分离到它们各自的类中.
这里要注意的另一件事是因为Location是一个类,它不是一个实体.
它是一个值类型对象,它没有自己的主键.
它与...保存在同一个表中包含它的学生.
这就是我们在这里使用该组件的原因.
这样可以灵活地更改我们的类层,如何定义类以及如何布局数据库.