NHibernate延迟加载

代码
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异常。

 

你可能感兴趣的:(Hibernate)