
(1)测试数据库与测试数据
Database目录下面是测试用的数据库文件NHibernatePractice2.mdf,包含有两张数据表Department与Employee,其中Employee表的DepartmentId是外键,引用Department的主键。表中测试数据如下:
为了测试方便,你可以直接附加数据库文件NHibernatePractice2.mdf到SQL Server2005,否则也可以自己创建数据库,然后手工(或使用NHibernate的SchemaExport)创建数据表、插入测试数据。
(2) 引用的类库Lib
Lib目录下面是引用的dll,包括:NHibernate.dll、nunit.framework.dll、Castle.DynamicProxy2.dll、Iesi.Collections.dll、log4net.dll。为项目添加这些引用。
(3)hibernate.cfg.xml
创建NHibernate配置文件,注意该文件属性设置为“Copy always”:配置如下:
Code
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<!--根据你自己的情况修改数据库驱动、数据库链接字符-->
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Server=(local);Initial Catalog=NHibernatePractice2;Integrated Security=SSPI</property>
<property name="show_sql">true</property>
<mapping assembly="NHibernatePractice2"/>
</session-factory>
</hibernate-configuration>
(4)NHibernateHelper.cs
接下来创建NHibernate辅助类,用于获取NHibernate的session,其中应用了Singleton模式:
Code
namespace NHibernatePractice2
{
//辅助类,用于获取Session
//应用了Singleton设计模式
public class NHibernateHelper
{
//Eagerly Initialize,确保线程同步
private static ISessionFactory _sessionFactory =
new Configuration().Configure().BuildSessionFactory();
private NHibernateHelper()
{
}
public static ISession OpenSession()
{
return _sessionFactory.OpenSession();
}
}
}
(5)Domain Class
在Domain目录下面创建两个实体类,代码非常简单,分别如下:
Department.cs:
Code
namespace NHibernatePractice2.Domain
{
public class Department
{
public virtual int Id { get; set; }
public virtual String Name { get; set; }
//关联集合
public virtual IList<Employee> Employees { get; set; }
}
}
Employee.cs:
Code
namespace NHibernatePractice2.Domain
{
public class Employee
{
public virtual int Id { get; set; }
public virtual String Name { get; set; }
public virtual Department Department { get; set; }
}
}
(6)Mapping文件
在Mappings目录下为Department与Employee分别创建映射文件(注意文件属性设置为“Embedded Resource”):
Department.hbm.xml:
Code
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernatePractice2"
namespace="NHibernatePractice2.Domain">
<class name="Department">
<id name="Id" >
<generator class="native" />
</id>
<property name="Name"/>
<!-- 设置fetch="join"抓取策略(global fetching strategy)-->
<!--该策略会被HQL忽略,但是不会被Get、Criteria忽略-->
<bag name="Employees" inverse="true" fetch="join">
<key column="DepartmentId" />
<one-to-many class="Employee"/>
</bag>
<!--若设置成lazy="false"(global fetch plan)-->
<!--则都不会被HQL、Get、Criteria忽略-->
<!--<bag name="Employees" inverse="true" lazy="false">
<key column="DepartmentId" />
<one-to-many class="Employee"/>
</bag>-->
</class>
</hibernate-mapping>
Employee.hbm.xml:
Code
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernatePractice2"
namespace="NHibernatePractice2.Domain">
<class name="Employee">
<id name="Id" >
<generator class="native" />
</id>
<property name="Name"/>
<many-to-one name="Department" class ="Department" column="DepartmentId" foreign-key="FK_Employee_Department" not-null="true"/>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernatePractice2"
namespace="NHibernatePractice2.Domain">
<class name="Employee">
<id name="Id" >
<generator class="native" />
</id>
<property name="Name"/>
<many-to-one name="Department" class ="Department" column="DepartmentId" foreign-key="FK_Employee_Department" not-null="true"/>
</class>
</hibernate-mapping> 大家注意到,我在Department.hbm.xml文件中将关联集合已经设置为fetch="join"。
(7)测试类NHibernatePractice2Test.cs
在Test目录下创建测试类NHibernatePractice2Test.cs,代码如下:
Code
namespace NHibernatePractice2.Test
{
[TestFixture]
public class NHibernatePractice2Test
{
//要查找的Department数据的Id=1
int departmentId = 1;
[Test]
//测试Get方法获取数据
public void TestGet()
{
Department fromDb = null;
//如果mapping文件中设置了fetch="join",
//Get查询会在一条sql中同时获取Department以及所属的Employee
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
//调用Get方法
fromDb = session.Get<Department>(departmentId);
transaction.Commit();
}
Assert.IsNotNull(fromDb);
//由于上面的Get查询同时获取了Department以及所属的Employee,测试成功
Assert.AreEqual(2, fromDb.Employees.Count);
}
[Test]
//测试Criteria获取数据
public void TestGetByCriteria()
{
Department fromDb = null;
//如果mapping文件中设置了fetch="join",
//Criteria查询会在一条sql中同时获取Department以及所属的Employee
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
fromDb = session.CreateCriteria(typeof(Department))
.Add(Restrictions.Eq("Id", departmentId))
.UniqueResult<Department>();
transaction.Commit();
}
Assert.IsNotNull(fromDb);
//由于上面的Criteria查询同时获取了Department以及所属的Employee,测试成功
Assert.AreEqual(2, fromDb.Employees.Count);
}
[Test]
//测试HQL获取数据
public void TestGetByHQL()
{
Department fromDb = null;
//如果mapping文件中设置了fetch="join",
//HQL查询会忽略fetch="join",因此只获取Department,不会获取Employee
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
fromDb = session.CreateQuery("from Department d where Id=:id")
.SetInt32("id", departmentId)
.UniqueResult<Department>();
transaction.Commit();
}
Assert.IsNotNull(fromDb);
//由于上面HQL查询只获取Department,没有获取Employee(也就是关联集合Employees未被初始化),
//同时session已经关闭(transaction.Commit),所以访问关联集合fromDb.Employees将抛出异常NHibernate.LazyInitializationException
Assert.AreEqual(2, fromDb.Employees.Count);
}
}
}
由于例子本身就非常简单,再加上已对代码进行了详细的注释,所以我这里只做个简单的介绍。3个测试方法TestGet()、TestGetByCriteria()、TestGetByHQL(),分别测试NHibernate的Get、Criteria和HQL获取数据。这里要注意的是,每个测试方法在验证前都进行了transaction.Commit();,效果就是关闭当前session,使查询得到的实体数据处于detached状态。如果在获取Department数据时没有加载Employees集合数据,这样当验证Assert.AreEqual(2, fromDb.Employees.Count);时会抛出NHibernate.LazyInitializationException异常。
Database目录下面是测试用的数据库文件NHibernatePractice2.mdf,包含有两张数据表Department与Employee,其中Employee表的DepartmentId是外键,引用Department的主键。表中测试数据如下:
为了测试方便,你可以直接附加数据库文件NHibernatePractice2.mdf到SQL Server2005,否则也可以自己创建数据库,然后手工(或使用NHibernate的SchemaExport)创建数据表、插入测试数据。
(2) 引用的类库Lib
Lib目录下面是引用的dll,包括:NHibernate.dll、nunit.framework.dll、Castle.DynamicProxy2.dll、Iesi.Collections.dll、log4net.dll。为项目添加这些引用。
(3)hibernate.cfg.xml
创建NHibernate配置文件,注意该文件属性设置为“Copy always”:配置如下:
Code
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<!--根据你自己的情况修改数据库驱动、数据库链接字符-->
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Server=(local);Initial Catalog=NHibernatePractice2;Integrated Security=SSPI</property>
<property name="show_sql">true</property>
<mapping assembly="NHibernatePractice2"/>
</session-factory>
</hibernate-configuration>
(4)NHibernateHelper.cs
接下来创建NHibernate辅助类,用于获取NHibernate的session,其中应用了Singleton模式:
Code
namespace NHibernatePractice2
{
//辅助类,用于获取Session
//应用了Singleton设计模式
public class NHibernateHelper
{
//Eagerly Initialize,确保线程同步
private static ISessionFactory _sessionFactory =
new Configuration().Configure().BuildSessionFactory();
private NHibernateHelper()
{
}
public static ISession OpenSession()
{
return _sessionFactory.OpenSession();
}
}
}
(5)Domain Class
在Domain目录下面创建两个实体类,代码非常简单,分别如下:
Department.cs:
Code
namespace NHibernatePractice2.Domain
{
public class Department
{
public virtual int Id { get; set; }
public virtual String Name { get; set; }
//关联集合
public virtual IList<Employee> Employees { get; set; }
}
}
Employee.cs:
Code
namespace NHibernatePractice2.Domain
{
public class Employee
{
public virtual int Id { get; set; }
public virtual String Name { get; set; }
public virtual Department Department { get; set; }
}
}
(6)Mapping文件
在Mappings目录下为Department与Employee分别创建映射文件(注意文件属性设置为“Embedded Resource”):
Department.hbm.xml:
Code
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernatePractice2"
namespace="NHibernatePractice2.Domain">
<class name="Department">
<id name="Id" >
<generator class="native" />
</id>
<property name="Name"/>
<!-- 设置fetch="join"抓取策略(global fetching strategy)-->
<!--该策略会被HQL忽略,但是不会被Get、Criteria忽略-->
<bag name="Employees" inverse="true" fetch="join">
<key column="DepartmentId" />
<one-to-many class="Employee"/>
</bag>
<!--若设置成lazy="false"(global fetch plan)-->
<!--则都不会被HQL、Get、Criteria忽略-->
<!--<bag name="Employees" inverse="true" lazy="false">
<key column="DepartmentId" />
<one-to-many class="Employee"/>
</bag>-->
</class>
</hibernate-mapping>
Employee.hbm.xml:
Code
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernatePractice2"
namespace="NHibernatePractice2.Domain">
<class name="Employee">
<id name="Id" >
<generator class="native" />
</id>
<property name="Name"/>
<many-to-one name="Department" class ="Department" column="DepartmentId" foreign-key="FK_Employee_Department" not-null="true"/>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernatePractice2"
namespace="NHibernatePractice2.Domain">
<class name="Employee">
<id name="Id" >
<generator class="native" />
</id>
<property name="Name"/>
<many-to-one name="Department" class ="Department" column="DepartmentId" foreign-key="FK_Employee_Department" not-null="true"/>
</class>
</hibernate-mapping> 大家注意到,我在Department.hbm.xml文件中将关联集合已经设置为fetch="join"。
(7)测试类NHibernatePractice2Test.cs
在Test目录下创建测试类NHibernatePractice2Test.cs,代码如下:
Code
namespace NHibernatePractice2.Test
{
[TestFixture]
public class NHibernatePractice2Test
{
//要查找的Department数据的Id=1
int departmentId = 1;
[Test]
//测试Get方法获取数据
public void TestGet()
{
Department fromDb = null;
//如果mapping文件中设置了fetch="join",
//Get查询会在一条sql中同时获取Department以及所属的Employee
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
//调用Get方法
fromDb = session.Get<Department>(departmentId);
transaction.Commit();
}
Assert.IsNotNull(fromDb);
//由于上面的Get查询同时获取了Department以及所属的Employee,测试成功
Assert.AreEqual(2, fromDb.Employees.Count);
}
[Test]
//测试Criteria获取数据
public void TestGetByCriteria()
{
Department fromDb = null;
//如果mapping文件中设置了fetch="join",
//Criteria查询会在一条sql中同时获取Department以及所属的Employee
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
fromDb = session.CreateCriteria(typeof(Department))
.Add(Restrictions.Eq("Id", departmentId))
.UniqueResult<Department>();
transaction.Commit();
}
Assert.IsNotNull(fromDb);
//由于上面的Criteria查询同时获取了Department以及所属的Employee,测试成功
Assert.AreEqual(2, fromDb.Employees.Count);
}
[Test]
//测试HQL获取数据
public void TestGetByHQL()
{
Department fromDb = null;
//如果mapping文件中设置了fetch="join",
//HQL查询会忽略fetch="join",因此只获取Department,不会获取Employee
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
fromDb = session.CreateQuery("from Department d where Id=:id")
.SetInt32("id", departmentId)
.UniqueResult<Department>();
transaction.Commit();
}
Assert.IsNotNull(fromDb);
//由于上面HQL查询只获取Department,没有获取Employee(也就是关联集合Employees未被初始化),
//同时session已经关闭(transaction.Commit),所以访问关联集合fromDb.Employees将抛出异常NHibernate.LazyInitializationException
Assert.AreEqual(2, fromDb.Employees.Count);
}
}
}
由于例子本身就非常简单,再加上已对代码进行了详细的注释,所以我这里只做个简单的介绍。3个测试方法TestGet()、TestGetByCriteria()、TestGetByHQL(),分别测试NHibernate的Get、Criteria和HQL获取数据。这里要注意的是,每个测试方法在验证前都进行了transaction.Commit();,效果就是关闭当前session,使查询得到的实体数据处于detached状态。如果在获取Department数据时没有加载Employees集合数据,这样当验证Assert.AreEqual(2, fromDb.Employees.Count);时会抛出NHibernate.LazyInitializationException异常。