Spring.NET学习笔记18——整合NHibernate(基础篇) Level 300

  NHibernate是一个基于.Net的针对关系型数据库的对象持久化(ORM)类库。NHibernate来源于非常优秀的基于Java的NHibernate关系型持久化工具。从数据库底NHibernate来持久化你的.Net 对象到关系型数据库。NHibernate为你处理这些,远胜于你不得不写SQL去从数据库存取对象。你的代码仅仅和对象关联,NHibernate自动产生SQL语句,并确保对象提交到正确的表和字段中去。

  Spring.NETNHibernate提供了很好的支持与封装。Spring.Data.NHibernate.Generic.SupportSpring.Data.NHibernate.Support下的HibernateDaoSupport是Spring.NET提供的数据库访问对象(DAO)的基类,两者的却别在于对泛型的支持程度。我们以Spring.Data.NHibernate.Generic.Support.HibernateDaoSupport为例,讲解Spring.NET整合NHibernate开发。

  我归纳了一下,分为三个步骤:

  一、实体对象的建立及配置

  二、数据访问对象建立及配置

  三、业务处理层建立及配置

 

  首先让我们学习一下NHibernate的实体对象的映射:我建立两个实体“用户信息”和“公司信息”。图1所示。

图1

 


     public  class User
    {
         public  virtual  int? UserID {  getset; }
         public  virtual  string UserName {  getset; }
         public  virtual  int UserAge {  getset; }
         public  virtual  bool UserSex {  getset; }

         public  virtual Company CurrentCompany {  getset; }
    }

     public  class Company
    {
         public  virtual  int? CompanyID {  getset; }
         public  virtual  string CompanyName {  getset; }

         public  virtual IList<User> UserList {  getset; }
    }

  
  NHibernate要求实体必须是带有无参构造函数和带有virtual修饰的属性。两个实体的关系是双向(一对多——多对一)映射关系。

 


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" namespace="Model">
   < class  name ="Model.User, Model"  table ="UserInfo" >
    
     < id  name ="UserID"  column ="UserID"  type ="int"   >
       < generator  class ="native"   />
     </ id >

     < property  name ="UserName"  column ="UserName"  type ="string"  length ="50"  not-null ="true" />
     < property  name ="UserAge"  column ="UserAge"  type ="int" />
     < property  name ="UserSex"  column ="UserSex"  type ="bool" />

     < many-to-one  name ="CurrentCompany"  class ="Model.Company, Model"  foreign-key ="FK_UserInfo_CompanyInfo" >
       < column  name ="CompanyID"  not-null ="true"   />
     </ many-to-one >

   </ class >
</ hibernate-mapping >


< hibernate-mapping  xmlns ="urn:nhibernate-mapping-2.2"  assembly ="Model"  namespace ="Model" >
   < class  name ="Model.Company, Model"  table ="CompanyInfo" >
    
     < id  name ="CompanyID"  column ="CompanyID"  type ="int"   >
       < generator  class ="native"   />
     </ id >

     < property  name ="CompanyName"  column ="Name"  type ="string"  not-null ="true"  length ="50" />

     < bag  name ="UserList"  inverse ="true"  cascade ="all-delete-orphan"  table ="UserInfo" >
       < key  column ="CompanyID"  foreign-key ="FK_UserInfo_CompanyInfo" />
       < one-to-many  class ="Model.User, Model"   />
     </ bag >

   </ class >
</ hibernate-mapping >

 

  以上就是实体对象与数据的映射文件,提供的配置我不详细说明,请查看NHibernate的帮助手册。

  接下来,我建立数据库访问对象(DAO)层。在这里我使用了泛型Repository模式。

 


     public  interface IRepository<T>
    {
         void Delete(T entity);
        T Get( object id);
         object Save(T entity);
         void Update(T entity);
    }

    public  class NHibernateRepository<T> : HibernateDaoSupport, IRepository<T>
    {
         public  object Save(T entity)
        {
             return  this.HibernateTemplate.Save(entity);
        }

         public T Get( object id)
        {
             return  this.HibernateTemplate.Get<T>(id);
        }

         public  void Update(T entity)
        {
             this.HibernateTemplate.Update(entity);
        }

         public  void Delete(T entity)
        {
             this.HibernateTemplate.Delete(entity);
        }
    }

 

  数据库访问对象我们可以让它继承于HibernateDaoSupport类,该类的HibernateTemplate属性我们可以通过Spring.NET从外部注入。

 


<?xml version="1.0" encoding="utf-8" ?>
< objects  xmlns ="http://www.springframework.net"
         xmlns:db
="http://www.springframework.net/database" >
   <!--  用以我们在其它的应用程序中,配置数据访问  -->
   < object  type ="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core" >
     < property  name ="ConfigSections"  value ="databaseSettings" />
   </ object >

   <!--  数据库和Nhibernate的相关配置  -->
   < db:provider  id ="DbProvider"  provider ="SqlServer-1.1"  
               connectionString
="Server=${db.datasource};database=${db.database};uid=${db.user};pwd=${db.password};" />

   <!-- SessionFactory对象,其中包括一些比较重要的属性  -->
   < object  id ="NHibernateSessionFactory"  type ="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate21" >
     < property  name ="DbProvider"  ref ="DbProvider" />
     < property  name ="MappingAssemblies" >
       < list >
         < value >Model </ value >
       </ list >
     </ property >
     < property  name ="HibernateProperties" >
       < dictionary >
         < entry  key ="hibernate.connection.provider"  value ="NHibernate.Connection.DriverConnectionProvider" />
         < entry  key ="dialect"  value ="NHibernate.Dialect.MsSql2000Dialect" />
         < entry  key ="hibernate.connection.driver_class"  value ="NHibernate.Driver.SqlClientDriver" />
         < entry  key ="use_outer_join"  value ="true" />
         < entry  key ="show_sql"  value ="false" />
         <!-- 自动建表(反向映射) -->
         < entry  key ="hbm2ddl.auto"  value ="update" />
         < entry  key ="adonet.batch_size"  value ="10" />
         < entry  key ="command_timeout"  value ="60" />
         <!-- 显式启用二级缓存 -->
         < entry  key ="cache.use_second_level_cache"  value ="true" />
         <!-- 启动查询缓存 -->
         < entry  key ="cache.use_query_cache"  value ="false" />
         < entry  key ="query.substitutions"  value ="true 1, false 0, yes 'Y', no 'N" />
         < entry  key ="proxyfactory.factory_class"  value ="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" />
       </ dictionary >
     </ property >
     < property  name ="ExposeTransactionAwareSessionFactory"  value ="true"   />
   </ object >

   < object  id ="HibernateTemplate"  type ="Spring.Data.NHibernate.Generic.HibernateTemplate" >
     < property  name ="SessionFactory"  ref ="NHibernateSessionFactory"   />
     < property  name ="TemplateFlushMode"  value ="Auto"   />
     < property  name ="CacheQueries"  value ="true"   />
   </ object >

   < object  id ="repository.user"  type ="Repository.NHibernateRepository&lt;Model.User>, Repository" >
     < property  name ="HibernateTemplate"  ref ="HibernateTemplate" />
   </ object >

   < object  id ="repository.company"  type ="Repository.NHibernateRepository&lt;Model.Company>, Repository" >
     < property  name ="HibernateTemplate"  ref ="HibernateTemplate" />
   </ object >


</ objects >

 

  db:provider节点是数据的连接字符串配置,我们引入xmlns:db="http://www.springframework.net/database这项命名空间便可以使用它。其中provider属性为数据库提供者的名称。以下是provider的详细情况:

名称

介绍

SqlServer-1.1

Microsoft SQL Server, provider V1.0.5.0 in framework .NET V1.1

SqlServer-2.0

Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0

SqlServerCe-3.1

Microsoft SQL Server Compact Edition, provider V9.0.242.0

SqlServerCe-3.5.1

Microsoft SQL Server Compact Edition, provider V3.5.1.0

OleDb-1.1

provider V1.0.5000.0 in framework .NET V1.1

OleDb-2.0

provider V2.0.0.0 in framework .NET V2.0

OracleClient-2.0

Oracle, Microsoft provider V2.0.0.0

OracleODP-2.0

Oracle, Oracle provider V2.102.2.20

MySql

MySQL provider 1.0.10.1

MySql-1.0.9

MySQL provider 1.0.9

MySql-5.0

MySQL provider 5.0.7.0

MySql-5.0.8.1

MySQL provider 5.0.8.1

MySql-5.1

MySQL provider 5.1.2.2

MySql-5.1.4

MySQL provider 5.1.2.2

MySql-5.2.3

MySQL provider 5.2.3.0

Npgsql-1.0

Postgresql provider 1.0.0.0 (and 1.0.0.1 - were build with same version info)

Npgsql-2.0 -beta1

Postgresql provider 1.98.1.0 beta 1

Npgsql-2.0

Postgresql provider 2.0.0.0

DB2-9.0.0-1.1

IBM DB2 Data Provider 9.0.0 for .NET Framework 1.1

DB2-9.0.0-2.0

IBM DB2 Data Provider 9.0.0 for .NET Framework 2.0

DB2-9.1.0-1.1

IBM DB2 Data Provider 9.1.0 for .NET Framework 1.1

DB2-9.1.0.2

IBM DB2 Data Provider 9.1.0 for .NET Framework 2.

SQLite-1.0.43

SQLite provider 1.0.43 for .NET Framework 2.0

SQLite-1.0.47

SQLite provider 1.0.43 for .NET Framework 2.0

SybaseAse-12

Sybase ASE provider for ASE 12.x

SybaseAse-15

Sybase ASE provider for ASE 15.x

SybaseAse-AdoNet2

Sybase ADO.NET 2.0 provider for ASE 12.x and 15.x

Odbc-1.1

ODBC provider V1.0.5000.0 in framework .NET V1.1

Odbc-2.0

ODBC provider V2.0.0.0 in framework .NET V2

InterSystems.Data.CacheClient

Caché provider Version 2.0.0.1 in framework .NET V2

 

  可以根据自己的数据库选择不同的提供者名称。connectionString属性为数据库的连接字符串,这里用${xxx}的方式来表示一个占位符,因为我们经常将Spring.NET的配置文件设置为“嵌入系统资源”,这样一来在程序编译后就不能够修改,所以我们就要在应用程序配置文件中填写连接字符串,而不是在Spring.NET的配置文件中填写。

 


<configuration>

< configSections >
< section  name ="databaseSettings"  type ="System.Configuration.NameValueSectionHandler" />
</ configSections >

   <!-- 数据库连接字符串 -->
   < databaseSettings >
     < add  key ="db.datasource"  value ="."   />
     < add  key ="db.user"  value ="sa"   />
     < add  key ="db.password"  value =""   />
     < add  key ="db.database"  value ="SpringNet_Lesson18"   />
   </ databaseSettings >

</ configuration >

   

  NHibernate中的Session控制取决于SessionFactorySpring.NET提供了LocalSessionFactoryObject类来统一管理SessionFactory。其中MappingAssemblies属性为实体程序集的名称,可以填写多个名称。HibernatePropertiesNHibernate的配置,dialect属性为数据库的方言,因为是SQL server 2K数据库,所以使用NHibernate.Dialect.MsSql2000Dialect proxyfactory.factory_class属性为延迟加载的代理类驱动,在NHibernate 2.1版中必须配置。hbm2ddl.auto属性为反向建立映射表的配置,我们配置为update后,NHibernate会帮我们自动根据实体的结构生成数据库中的表。

 

  接下来我们看一下业务处理层。

 


     public  interface IUserManager
    {
         void Delete(User entity);
        User Get( object id);
         object Save(User entity);
         void Update(User entity);
        IRepository<User> UserRepository {  getset; }
    }

     public  class UserManager : IUserManager
    {
         public IRepository<User> UserRepository {  getset; }

         public  object Save(User entity)
        {
             return  this.UserRepository.Save(entity);
        }

         public  void Delete(User entity)
        {
             this.UserRepository.Delete(entity);
        }

         public User Get( object id)
        {
             return  this.UserRepository.Get(id);
        }

         public  void Update(User entity)
        {
             this.UserRepository.Update(entity);
        }
    }

 


     public  interface ICompanyManager
    {
         void Delete( object id);
        Company Get( object id);
         object Save(Company entity);
         void Update(Company entity);
    }

     public  class CompanyManager : ICompanyManager
    {
         public IRepository<Company> CompanyRepository {  getset; }

         public  object Save(Company entity)
        {
             return  this.CompanyRepository.Save(entity);
        }

         public  void Delete( object id)
        {
             this.CompanyRepository.Delete( this.Get(id));
        }

         public Company Get( object id)
        {
             return  this.CompanyRepository.Get(id);
        }

         public  void Update(Company entity)
        {
            Company company =  this.Get(entity.CompanyID);
            company.CompanyName = entity.CompanyName;
             this.CompanyRepository.Update(company);
        }
    }

 

  代码的编写我不仔细讲,我们主要学习一下相关的配置。

 


<?xml version="1.0" encoding="utf-8" ?>
< objects  xmlns ="http://www.springframework.net" >

   < object  id ="transactionManager"
        type
="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate21" >
     < property  name ="DbProvider"  ref ="DbProvider" />
     < property  name ="SessionFactory"  ref ="NHibernateSessionFactory" />
   </ object >


   < object  id ="transactionInterceptor"  type ="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data" >
     < property  name ="TransactionManager"  ref ="transactionManager" />
     < property  name ="TransactionAttributeSource" >
       < object  type ="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data" />
     </ property >
   </ object >

   < object  id ="BaseTransactionManager"   type ="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data"  abstract ="true" >
     < property  name ="PlatformTransactionManager"  ref ="transactionManager" />
     < property  name ="TransactionAttributes" >
       < name-values >
         < add  key ="Save*"  value ="PROPAGATION_REQUIRED" />
         < add  key ="Set*"  value ="PROPAGATION_REQUIRED" />
         < add  key ="Finish*"  value ="PROPAGATION_REQUIRED" />
         < add  key ="Update*"  value ="PROPAGATION_REQUIRED" />
         < add  key ="Delete*"  value ="PROPAGATION_REQUIRED" />
         < add  key ="Add*"  value ="PROPAGATION_REQUIRED" />
         < add  key ="Get*"  value ="PROPAGATION_SUPPORTS,readOnly" />
         < add  key ="Find*"  value ="PROPAGATION_SUPPORTS,readOnly" />
         < add  key ="Load*"  value ="PROPAGATION_SUPPORTS,readOnly" />
         < add  key ="*"  value ="PROPAGATION_REQUIRED" />
       </ name-values >
     </ property >
   </ object >

   < object  id ="CompanyManager"  parent ="BaseTransactionManager" >
     < property  name ="Target" >
       < object  type ="Manager.CompanyManager,Manager" >
         < property  name ="CompanyRepository"  ref ="repository.company" />
       </ object >
     </ property >
   </ object >

   < object  id ="UserManager"  parent ="BaseTransactionManager" >
     < property  name ="Target" >
       < object  type ="Manager.UserManager,Manager" >
         < property  name ="UserRepository"  ref ="repository.user" />
       </ object >
     </ property >
   </ object >

</ objects >

 

  我们在前几篇学过AOP拦截和事务代理。Spring.NETNHibernate提供的事务代理是TransactionProxyFactoryObject。我们将改类的Target熟悉注入业务处理层的类,这样Spring.NET会为该类包装上事务。

 

  最后我们写一个单元测试类,对业务层进行单元测试。


[TestFixture]
     public  class UserManagerTest 
    {
         static log4net.ILog logger = log4net.LogManager.GetLogger( " Logger ");

        [SetUp]
         public  void SetUp()
        {
             try
            {
                log4net.Config.XmlConfigurator.Configure();
                IApplicationContext applicationContext = ContextRegistry.GetContext();
                userManager = (IUserManager)applicationContext.GetObject( " UserManager ");
                companyManager = (ICompanyManager)applicationContext.GetObject( " CompanyManager ");
            }
             catch (Exception ex)
            {
                logger.Error(ex);
                 throw ex;
            }
        }

         private IUserManager userManager;
         private ICompanyManager companyManager;

        [Test]
         public  void Delete()
        {
            userManager.Delete(userManager.Get( 2));
        }

        [Test]
         public  void Get()
        {
            User user = userManager.Get( 1);
        }

        [Test]
         public  void Save()
        {
            User user =  new User();
            user.UserName =  " 刘冬 ";
            user.CurrentCompany = companyManager.Get( 1);
            userManager.Save(user);
        }

        [Test]
         public  void Update()
        {
            User user = userManager.Get( 1);
            user.UserName =  " 刘冬冬 ";
            userManager.Update(user);
        }
    }

 


[TestFixture]
     public  class CompanyManagerTest 
    {
         static log4net.ILog logger = log4net.LogManager.GetLogger( " Logger ");

        [SetUp]
         public  void SetUp()
        {
             try
            {
                log4net.Config.XmlConfigurator.Configure();
                IApplicationContext applicationContext = ContextRegistry.GetContext();
                companyManager = (ICompanyManager)applicationContext.GetObject( " CompanyManager ");
            }
             catch (Exception ex)
            {
                logger.Error(ex);
                 throw ex;
            }
        }

         private ICompanyManager companyManager;

        [Test]
         public  void Delete()
        {
            companyManager.Delete( 4);
        }

        [Test]
         public  void Get()
        {
            Company company = companyManager.Get( 1);
        }

        [Test]
         public  void Save()
        {
            Company company =  new Company();
            company.CompanyName =  " 刘冬公司 ";
            companyManager.Save(company);
        }

        [Test]
         public  void Update()
        {
            Company company = companyManager.Get( 1);
            company.CompanyName =  " 刘冬冬公司 ";
            companyManager.Update(company);
        }
    }

 

  配置文件:


<?xml version="1.0" encoding="utf-8" ?>
< configuration >
  
   < configSections >
     < sectionGroup  name ="spring" >
       < section  name ="context"  type ="Spring.Context.Support.ContextHandler, Spring.Core" />
       < section  name ="objects"  type ="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
       < section  name ="parsers"  type ="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
     </ sectionGroup >
    
     < section  name ="databaseSettings"  type ="System.Configuration.NameValueSectionHandler" />
     < section  name ="log4net"  type ="log4net.Config.Log4NetConfigurationSectionHandler,log4net"   />

   </ configSections >

   < spring >
     < parsers >
       < parser  type ="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
       < parser  type ="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" />
     </ parsers >
     < context >
       < resource  uri ="assembly://Repository/Repository/Repository.xml" />
       < resource  uri ="assembly://Manager/Manager/Manager.xml" />
     </ context >

   </ spring >

   < log4net >
     < appender  name ="ConsoleAppender"  type ="log4net.Appender.ConsoleAppender" >
       < layout  type ="log4net.Layout.PatternLayout" >
         < conversionPattern  value ="%-5level %logger - %message%newline"   />
       </ layout >
     </ appender >

     <!--  Set default logging level to DEBUG  -->
     < root >
       < level  value ="DEBUG"   />
       < appender-ref  ref ="ConsoleAppender"   />
     </ root >

     <!--  Set logging for Spring.  Logger names in Spring correspond to the namespace  -->
     < logger  name ="Spring" >
       < level  value ="INFO"   />
     </ logger >

     < logger  name ="Spring.Data" >
       < level  value ="DEBUG"   />
     </ logger >

     < logger  name ="NHibernate" >
       < level  value ="INFO"   />
     </ logger >


   </ log4net >

   <!-- 数据库连接字符串 -->
   < databaseSettings >
     < add  key ="db.datasource"  value ="."   />
     < add  key ="db.user"  value ="sa"   />
     < add  key ="db.password"  value =""   />
     < add  key ="db.database"  value ="SpringNet_Lesson18"   />
   </ databaseSettings >

</ configuration >

 

 

  代码下载

 

  数据库我没有上传,因为空间的问题。我设置了自动建表的属性,可以用来自动创建数据库表结构。

 

  返回目录

作者:刘冬.NET 博客地址:http://www.cnblogs.com/GoodHelper/ 欢迎转载,但须保留版权
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值