NHibernate详解
目录
2.1 the Plain Old CLR Object (POCO). 21
1配置起步
1.1环境支持
1.1.1 版本
NHibernate: 1.2.0 .3001
.net: v2.0.50727
1.1.2 数据库
sqlserver2005,新建库为quickstart。
1.1.3 测试用表
关系图:
说明:Cat中的CatId是自增的。
SQL:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CatType]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[CatType](
[TypeID] [int] IDENTITY(1,1) NOT NULL,
[TypeName] [nvarchar](50) NULL,
CONSTRAINT [PK_CatType] PRIMARY KEY CLUSTERED
(
[TypeID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Cat]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Cat](
[CatId] [int] IDENTITY(1,1) NOT NULL,
[CatTypeID] [int] NOT NULL,
[Name] [nvarchar](16) NOT NULL,
[Sex] [nchar](1) NULL,
[Weight] [real] NULL,
CONSTRAINT [PK_Cat_1] PRIMARY KEY CLUSTERED
(
[CatId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CatDressScheme]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[CatDressScheme](
[DSID] [int] IDENTITY(1,1) NOT NULL,
[CatId] [int] NOT NULL,
[dsName] [nvarchar](50) NULL,
CONSTRAINT [PK_CatDressScheme_1] PRIMARY KEY CLUSTERED
(
[DSID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CatFoodScheme]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[CatFoodScheme](
[FSID] [int] IDENTITY(1,1) NOT NULL,
[CatId] [int] NOT NULL,
[scName] [nvarchar](50) NULL,
CONSTRAINT [PK_CatFoodScheme_1] PRIMARY KEY CLUSTERED
(
[FSID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CatTvPlan]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[CatTvPlan](
[TVID] [int] IDENTITY(1,1) NOT NULL,
[CatId] [int] NOT NULL,
[tvName] [nvarchar](50) NULL,
CONSTRAINT [PK_CatTvPlan] PRIMARY KEY CLUSTERED
(
[TVID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[CatPart]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[CatPart](
[CatId] [int] NOT NULL,
[PartName] [nvarchar](50) NULL,
CONSTRAINT [PK_CatPart_1] PRIMARY KEY CLUSTERED
(
[CatId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_CatDressScheme_Cat]') AND parent_object_id = OBJECT_ID(N'[dbo].[CatDressScheme]'))
ALTER TABLE [dbo].[CatDressScheme] WITH CHECK ADD CONSTRAINT [FK_CatDressScheme_Cat] FOREIGN KEY([CatId])
REFERENCES [dbo].[Cat] ([CatId])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_CatFoodScheme_Cat]') AND parent_object_id = OBJECT_ID(N'[dbo].[CatFoodScheme]'))
ALTER TABLE [dbo].[CatFoodScheme] WITH CHECK ADD CONSTRAINT [FK_CatFoodScheme_Cat] FOREIGN KEY([CatId])
REFERENCES [dbo].[Cat] ([CatId])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_CatTvPlan_Cat]') AND parent_object_id = OBJECT_ID(N'[dbo].[CatTvPlan]'))
ALTER TABLE [dbo].[CatTvPlan] WITH CHECK ADD CONSTRAINT [FK_CatTvPlan_Cat] FOREIGN KEY([CatId])
REFERENCES [dbo].[Cat] ([CatId])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_CatPart_Cat]') AND parent_object_id = OBJECT_ID(N'[dbo].[CatPart]'))
ALTER TABLE [dbo].[CatPart] WITH CHECK ADD CONSTRAINT [FK_CatPart_Cat] FOREIGN KEY([CatId])
REFERENCES [dbo].[Cat] ([CatId])
1.2在网站中配置NHibernate
简单的应用,比如仅仅在单个项目,如一个网站中使用,按此进行配置。
首先,引用NH。
1.2.1 配置web.config
<configuration>下直接新建如下(注意connection.connection_string到正确性;assembly按你要求灵活配置):
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
</configSections>
<!-- Add this element -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.connection_string">Data Source=XY-XPWY/SQLEXPRESS;Initial Catalog=quickstart;Integrated Security=True</property>
<mapping assembly="QuickStart" />
</session-factory>
</hibernate-configuration>
1.2.2 实体类
网站根目录下或实体层新建Cat.cs,CatDressScheme,CatFoodScheme,CatPart,CatTvPlan,CatType。值得一提的是,几个属性值的方法,要设置为virtual。这与NHibernate.Documentation.chm也有出入。
建议用CodeSmith 4.1.2 工具生成。在模板里面注意更改virtual。
Cat.cs示例
using System;
using System.Collections;
using System.Web.UI.WebControls;
namespace Stclass.StEntity
{
#region Cat
/// <summary>
/// Cat object for NHibernate mapped table 'Cat'.
/// </summary>
public class Cat : System.IComparable
{
#region Member Variables
protected int _id;
protected int _catTypeID;
protected string _name;
protected string _sex;
protected float _weight;
protected IList _catDressSchemes;
protected IList _catFoodSchemes;
protected IList _catTvPlans;
protected CatPart _catPart;
protected static String _sortExpression = "Id";
protected static SortDirection _sortDirection = SortDirection.Ascending;
#endregion
#region Constructors
public Cat() { }
public Cat( int catTypeID, string name, string sex, float weight )
{
this._catTypeID = catTypeID;
this._name = name;
this._sex = sex;
this._weight = weight;
}
#endregion
#region Public Properties
public virtual int Id
{
get {return _id;}
set {_id = value;}
}
public virtual int CatTypeID
{
get { return _catTypeID; }
set { _catTypeID = value; }
}
public virtual string Name
{
get { return _name; }
set
{
if ( value != null && value.Length > 16)
throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());
_name = value;
}
}
public virtual string Sex
{
get { return _sex; }
set
{
if ( value != null && value.Length > 1)
throw new ArgumentOutOfRangeException("Invalid value for Sex", value, value.ToString());
_sex = value;
}
}
public virtual float Weight
{
get { return _weight; }
set { _weight = value; }
}
public virtual IList CatDressSchemes
{
get
{
if (_catDressSchemes==null)
{
_catDressSchemes = new ArrayList();
}
return _catDressSchemes;
}
set { _catDressSchemes = value; }
}
public virtual IList CatFoodSchemes
{
get
{
if (_catFoodSchemes==null)
{
_catFoodSchemes = new ArrayList();
}
return _catFoodSchemes;
}
set { _catFoodSchemes = value; }
}
public virtual IList CatTvPlans
{
get
{
if (_catTvPlans==null)
{
_catTvPlans = new ArrayList();
}
return _catTvPlans;
}
set { _catTvPlans = value; }
}
public virtual CatPart CatPart
{
get { return _catPart; }
set { _catPart = value; }
}
public static String SortExpression
{
get { return _sortExpression; }
set { _sortExpression = value; }
}
public static SortDirection SortDirection
{
get { return _sortDirection; }
set { _sortDirection = value; }
}
#endregion
#region IComparable Methods
public int CompareTo(object obj)
{
if (!(obj is Cat))
throw new InvalidCastException("This object is not of type Cat");
int relativeValue;
switch (SortExpression)
{
case "Id":
relativeValue = this.Id.CompareTo(((Cat)obj).Id);
break;
case "CatTypeID":
relativeValue = this.CatTypeID.CompareTo(((Cat)obj).CatTypeID);
break;
case "Name":
relativeValue = this.Name.CompareTo(((Cat)obj).Name);
break;
case "Sex":
relativeValue = (this.Sex != null) ? this.Sex.CompareTo(((Cat)obj).Sex) : -1;
break;
case "Weight":
relativeValue = (this.Weight != null) ? this.Weight.CompareTo(((Cat)obj).Weight) : -1;
break;
default:
goto case "Id";
}
if (Cat.SortDirection == SortDirection.Ascending)
relativeValue *= -1;
return relativeValue;
}
#endregion
}
#endregion
}
CatDressScheme.cs示例
using System;
using System.Collections;
using System.Web.UI.WebControls;
namespace Stclass.StEntity
{
#region CatDressScheme
/// <summary>
/// CatDressScheme object for NHibernate mapped table 'CatDressScheme'.
/// </summary>
public class CatDressScheme : System.IComparable
{
#region Member Variables
protected int _id;
protected string _dsName;
protected Cat _cat;
protected static String _sortExpression = "Id";
protected static SortDirection _sortDirection = SortDirection.Ascending;
#endregion
#region Constructors
public CatDressScheme() { }
public CatDressScheme( string dsName, Cat cat )
{
this._dsName = dsName;
this._cat = cat;
}
#endregion
#region Public Properties
public virtual int Id
{
get {return _id;}
set {_id = value;}
}
public virtual string DsName
{
get { return _dsName; }
set
{
if ( value != null && value.Length > 50)
throw new ArgumentOutOfRangeException("Invalid value for DsName", value, value.ToString());
_dsName = value;
}
}
public virtual Cat Cat
{
get { return _cat; }
set { _cat = value; }
}
public static String SortExpression
{
get { return _sortExpression; }
set { _sortExpression = value; }
}
public static SortDirection SortDirection
{
get { return _sortDirection; }
set { _sortDirection = value; }
}
#endregion
#region IComparable Methods
public int CompareTo(object obj)
{
if (!(obj is CatDressScheme))
throw new InvalidCastException("This object is not of type CatDressScheme");
int relativeValue;
switch (SortExpression)
{
case "Id":
relativeValue = this.Id.CompareTo(((CatDressScheme)obj).Id);
break;
case "DsName":
relativeValue = (this.DsName != null) ? this.DsName.CompareTo(((CatDressScheme)obj).DsName) : -1;
break;
default:
goto case "Id";
}
if (CatDressScheme.SortDirection == SortDirection.Ascending)
relativeValue *= -1;
return relativeValue;
}
#endregion
}
#endregion
}
1.2.3 hbm.xml
与Cat.cs同级目录。建立完成后,其属性中的“高级”-“生成操作”设置为“嵌入的资源”。漏此,会很郁闷。且,NH文档未提。
建议用CodeSmith 4.1.2 生成。在模板里面注意更改xmlns="urn:nhibernate-mapping-2.2"。
Cat.hbm.xml示例
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Stclass.StEntity.Cat, Stclass.StEntity" table="Cat">
<id name="Id" type="Int32" unsaved-value="null">
<column name="CatId" length="4" sql-type="int" not-null="true" unique="true" index="PK_Cat_1"/>
<generator class="identity" />
</id>
<property name="CatTypeID" type="Int32">
<column name="CatTypeID" length="4" sql-type="int" not-null="true"/>
</property>
<property name="Name" type="String">
<column name="Name" length="16" sql-type="nvarchar" not-null="true"/>
</property>
<property name="Sex" type="String">
<column name="Sex" length="1" sql-type="nchar" not-null="false"/>
</property>
<property name="Weight" type="Single">
<column name="Weight" length="4" sql-type="real" not-null="false"/>
</property>
<bag name="CatDressSchemes" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="CatId"/>
<one-to-many class="Stclass.StEntity.CatDressScheme, Stclass.StEntity"/>
</bag>
<bag name="CatFoodSchemes" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="CatId"/>
<one-to-many class="Stclass.StEntity.CatFoodScheme, Stclass.StEntity"/>
</bag>
<bag name="CatTvPlans" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="CatId"/>
<one-to-many class="Stclass.StEntity.CatTvPlan, Stclass.StEntity"/>
</bag>
<one-to-one name="CatPart" class="Stclass.StEntity.CatPart, Stclass.StEntity">
</one-to-one>
</class>
</hibernate-mapping>
CatDressScheme.hbm.xml示例
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Stclass.StEntity.CatDressScheme, Stclass.StEntity" table="CatDressScheme">
<id name="Id" type="Int32" unsaved-value="null">
<column name="DSID" length="4" sql-type="int" not-null="true" unique="true" index="PK_CatDressScheme_1"/>
<generator class="identity" />
</id>
<property name="DsName" type="String">
<column name="dsName" length="50" sql-type="nvarchar" not-null="false"/>
</property>
<many-to-one name="Cat" class="Stclass.StEntity.Cat, Stclass.StEntity">
<column name="CatId" length="4" sql-type="int" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>
1.2.4 NHibernateHelper.cs
网站根目录下新建。
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NHibernate;
using NHibernate.Cfg;
namespace QuickStart
{
public sealed class NHibernateHelper
{
private const string CurrentSessionKey = "nhibernate.current_session";
private static readonly ISessionFactory sessionFactory;
static NHibernateHelper()
{
sessionFactory = new NHibernate.Cfg.Configuration().Configure().BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
currentSession = sessionFactory.OpenSession();
context.Items[CurrentSessionKey] = currentSession;
}
return currentSession;
}
public static void CloseSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
// No current session
return;
}
currentSession.Close();
context.Items.Remove(CurrentSessionKey);
}
public static void CloseSessionFactory()
{
if (sessionFactory != null)
{
sessionFactory.Close();
}
}
}
}
1.2.5 使用示例
ISession session = Stclass.StEntity.NHibernateHelper.GetCurrentSession();
ITransaction tx = session.BeginTransaction();
CatType ct = new CatType();
ct.TypeName = "xianluo";
IQuery query = session.CreateQuery("select c from CatType as c where c.TypeName = :tname");
query.SetString("tname", "xianluo");
if (query.List().Count > 0)
{
Response.Write("haved xianluo");
return;
}
session.Save(ct);
tx.Commit();
Response.Write("id:" + ct.Id + "<br/>");
Response.Write("name:" + ct.TypeName + "<br/>");
NHibernateHelper.CloseSession();
1.3在解决方案中配置NHibernate
建立空白解决方案。
然后在其下添加一网站,如:STWeb;
然后添加一类库SomeBLL,命名空间为Stclass.SomeBLL。假设该类库作为系统开发中的业务层;
然后添加一类库STEntity,命名空间为Stclass.StEntity。假设该类库作为系统开发中的业务层的实体类集。
注意NH的引用和各项目间的互相引用。
1.3.1 配置web.config?否
NH的配置即不在web.config,也不在STEntity的App.config。你需要在STWeb的BIN目录下新建hibernate.cfg.xml。其内容如(注意此处的assembly为STEntity,为实体类的类库名):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" sql-show="true"/>
</configSections>
<!-- Add this element -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<mapping resource="Stclass.StEntity.CatDressScheme.hbm.xml" assembly="Stclass.StEntity" />
<mapping resource="Stclass.StEntity.CatFoodScheme.hbm.xml" assembly="Stclass.StEntity" />
<mapping resource="Stclass.StEntity.CatPart.hbm.xml" assembly="Stclass.StEntity" />
<mapping resource="Stclass.StEntity.CatTvPlan.hbm.xml" assembly="Stclass.StEntity" />
<mapping resource="Stclass.StEntity.CatType.hbm.xml" assembly="Stclass.StEntity" />
<mapping resource="Stclass.StEntity.Cat.hbm.xml" assembly="Stclass.StEntity" />
</session-factory>
</hibernate-configuration>
</configuration>
1.3.2 实体类
同 1.2.2
1.3.3 hbm.xml
同 1.2.3
1.3.4 NHibernateHelper
该类命名空间仍在STEntity,当然也可以在其它BLL层。
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NHibernate;
using NHibernate.Cfg;
namespace Stclass.StEntity
{
public sealed class NHibernateHelper
{
private const string CurrentSessionKey = "nhibernate.current_session";
private static readonly ISessionFactory sessionFactory;
static NHibernateHelper()
{
sessionFactory = new NHibernate.Cfg.Configuration().Configure().BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
currentSession = sessionFactory.OpenSession();
context.Items[CurrentSessionKey] = currentSession;
}
return currentSession;
}
public static void CloseSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
// No current session
return;
}
currentSession.Close();
context.Items.Remove(CurrentSessionKey);
}
public static void CloseSessionFactory()
{
if (sessionFactory != null)
{
sessionFactory.Close();
}
}
}
}
1.3.5 使用示例
比如,在业务层中新建业务类Class1,其方法有void xxx(),代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using Stclass.StEntity;
namespace Stclass.SomeBLL
{
public class Class1
{
public void xxx()
{
ISession session = Stclass.StEntity.NHibernateHelper.GetCurrentSession();
ITransaction tx = session.BeginTransaction();
Cat princess = new Cat();
//princess.Id = "111";
princess.Name = "Prrrrr";
princess.Sex = 'F';
princess.Weight = 7.4f ;
session.Save(princess);
tx.Commit();
NHibernateHelper.CloseSession();
}
}
}
则,我们在表示层STWeb中
添加数据,如:
ISession session = Stclass.StEntity.NHibernateHelper.GetCurrentSession();
ITransaction tx = session.BeginTransaction();
Cat princess = new Cat();
//princess.Id = "111";
princess.Name = "Princessddd";
princess.Sex = 'F';
princess.Weight = 7.4f ;
session.Save(princess);
tx.Commit();
NHibernateHelper.CloseSession();
查询数据,如:
ISession session = Stclass.StEntity.NHibernateHelper.GetCurrentSession();
ITransaction tx = session.BeginTransaction();
IQuery query = session.CreateQuery("select c from Cat as c where c.Sex = :sex");
query.SetCharacter("sex", 'F');
foreach (Cat cat in query.Enumerable())
{
Response.Write("Female Cat: " + cat.Name + "<br/>");
}
tx.Commit();
1.4使用自定义配置
在实际使用过程中,由于存在多层设计,或其它因素,如出于安全考虑,隐藏数据库库连接字符串,或需要将字符串加密,则使用NH的配置文件就会带来局限性,故我们需要将配置独立出来。如配置部分代码改为:
NHibernate.Cfg.Configuration cfg = new Configuration();
cfg.SetProperty("hibernate.dialect", "NHibernate.Dialect.MsSql2005Dialect");
cfg.SetProperty("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");
cfg.SetProperty("hibernate.connection.connection_string", "Data Source=XY-XPWY//SQLEXPRESS;Initial Catalog=quickstart;Integrated Security=True");
sessionFactory = cfg.Configure().BuildSessionFactory();
这样一来,就可以将配置文件中的
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.connection_string">Data Source=XY-XPWY/SQLEXPRESS;Initial Catalog=quickstart;Integrated Security=True</property>
这一部分去掉。
而代码中加入的部分,属性设置部分VALUE的取值可以根据你本身项目的需要进行取得。
另外,也可以重新制定配置文件,NH默认的配置文件为WEB.CONFIG或者APP.CONFIG或者HIBERNATE.CFG.XML,以下代码用于更改配置文件:
ISessionFactory sf = new Configuration()
.Configure("/path/to/config.cfg.xml")
.BuildSessionFactory();