使用Spring.Net+NHibernate構建WCF應用


在企業級應用開發中,利用合適的框架針對不同項目構建相應的應用。Spring.Net作為Spring的.Net版本,具有很強大的應用。如:作為IoC容器、AOP處理框架、與NHibernate的集成、Spring.Net發布WebService\WCF服務等。而NHibernate作為一個優秀的ORM框架也廣受開發者的青睞。本文將通過Spring.Net+NHibernate來構建WCF應用。

 

本文要點:
  1. Spring.Net與NHibernate的集成應用
  2. Spring.Net注入WCF
  3. Entity與DTO對象之間的轉化 

 

先上一張結構圖:

 

 

正式介紹之前介紹一下框架 版本:

Spring.Net :1.3.2

NHibernate :3.2(目前Spring支持的NHibernate最高版本) 

 1、Spring.Net與NHibernate的集成應用

Spring.Net以及NHibernate的配置:

Spring.Net對NHibernate支持的配置(配置1):

<? xml version="1.0" encoding="utf-8"  ?>
< objects  xmlns ="http://www.springframework.net"  xmlns:db ="http://www.springframework.net/database" >
    <!--配置數據庫信息-->
     < db:provider  id ="dbProvider"  provider ="SqlServer-1.1"  connectionString ="Data Source=.\SqlExpress;Initial Catalog=SpringNHibernateCourseSystem;Integrated Security=True" ></ db:provider >
     < object  id ="NHibernateSessionFactory"  type ="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate32" >
         < property  name ="DbProvider"  ref ="dbProvider" ></ property >
         <!--配置NHibernate使用的實體程序集-- > 
< property  name ="MappingAssemblies" >
             < list >
                 < value >Domain </ value >
             </ list >
         </ property >
         <!--配置NHibernate的配置信息-- >  
< property  name ="HibernateProperties" >
             < dictionary >
                 < entry  key ="hibernate.connection.provider"  value ="NHibernate.Connection.DriverConnectionProvider" ></ entry >
                 < entry  key ="dialect"  value ="NHibernate.Dialect.MsSql2005Dialect" ></ entry >
                 < entry  key ="hibernate.connection.driver_class"  value ="NHibernate.Driver.SqlClientDriver" ></ entry >
                 < entry  key ="use_out_join"  value ="true" ></ entry >
                 < entry  key ="show_sql"  value ="true" ></ entry >
                 < entry  key ="hbm2ddl.auto"  value ="update" ></ entry >
                 < entry  key ="adonet.batch_size"  value ="10" ></ entry >
                 < entry  key ="command_timeout"  value ="10" ></ entry >
                 < entry  key ="cache.use_second_level_cache"  value ="true" ></ entry >
                 < entry  key ="cache.use_query_cache"  value ="true" ></ entry >
                 < entry  key ="query.substitutions"  value ="true 1, false 0, yes 'Y', no 'N" ></ entry >
             </ dictionary >
         </ property >
         < property  name ="ExposeTransactionAwareSessionFactory"  value ="true" ></ property >
     </ object >

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

 

Spring.Net自身的配置(配置2):

 

View Code 
 1 <?xml version= " 1.0 " encoding= " utf-8 " ?>
 2 <objects xmlns= " http://www.springframework.net " xmlns:db= " http://www.springframework.net/database ">
 3 
 4     <db:provider id= " dbProvider " provider= " SqlServer-1.1 " connectionString= " Data Source=.\SqlExpress;Initial Catalog=SpringNHibernateCourseSystem;Integrated Security=True "></db:provider>
 5     < object id= " NHibernateSessionFactory " type= " Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate32 ">
 6         <property name= " DbProvider "  ref= " dbProvider "></property>
 7         <property name= " MappingAssemblies ">
 8             <list>
 9                 <value>Domain</value>
10             </list>
11         </property>
12         <property name= " HibernateProperties ">
13             <dictionary>
14                 <entry key= " hibernate.connection.provider " value= " NHibernate.Connection.DriverConnectionProvider "></entry>
15                 <entry key= " dialect " value= " NHibernate.Dialect.MsSql2005Dialect "></entry>
16                 <entry key= " hibernate.connection.driver_class " value= " NHibernate.Driver.SqlClientDriver "></entry>
17                 <entry key= " use_out_join " value= " true "></entry>
18                 <entry key= " show_sql " value= " true "></entry>
19                 <entry key= " hbm2ddl.auto " value= " update "></entry>
20                 <entry key= " adonet.batch_size " value= " 10 "></entry>
21                 <entry key= " command_timeout " value= " 10 "></entry>
22                 <entry key= " cache.use_second_level_cache " value= " true "></entry>
23                 <entry key= " cache.use_query_cache " value= " true "></entry>
24                 <entry key= " query.substitutions " value= " true 1, false 0, yes 'Y', no 'N "></entry>
25             </dictionary>
26         </property>
27         <property name= " ExposeTransactionAwareSessionFactory " value= " true "></property>
28     </ object>
29 
30     < object id= " HibernateTemplate " type= " Spring.Data.NHibernate.Generic.HibernateTemplate ">
31         <property name= " SessionFactory "  ref= " NHibernateSessionFactory "></property>
32         <property name= " TemplateFlushMode " value= " Auto "></property>
33         <property name= " CacheQueries " value= " true "></property>
34     </ object>
35

 

 

注意:在此配置中,<resource >節點引用其他程序集下的配置(同NHibernate的映射文件一樣,被設置為"嵌入的資源"),請注意uri屬性的配置方式。

NHibernate映射的配置(配置3):

 

<!--StudentEntity.hbm.xml 文件-->
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain">
<class name="StudentEntity" table="`Student`">
<id name="Id" type="Int32" >
<column name="ID" length="4" sql-type="int" not-null="true" unique="true" index="PK_Student"/>
<generator class="native" />
</id>
<property name="Name" type="String">
<column name="Name" length="50" sql-type="nvarchar" not-null="false"/>
</property>
<property name="Sex" type="String">
<column name="Sex" length="1" sql-type="char" not-null="false"/>
</property>
<many-to-one name="Class" class="ClassEntity " >
<column name="ClassId" length="4" sql-type="int" not-null="false"/>
</many-to-one>
</class>
</hibernate-mapping>
 
<!--ClassEntity.hbm.xml 文件-->
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain">
<class name="ClassEntity" table="`Class`">
<id name="Id" type="Int32">
<column name="ID" length="4" sql-type="int" not-null="true" unique="true" index="PK_Class"/>
<generator class="native" />
</id>
<property name="Name" type="String" length="50">
<column name="Name" length="50" sql-type="varchar" not-null="false"/>
</property>
<bag name="Students" inverse="true" lazy="true" cascade="all">
<key column="ClassID" foreign-key="FK_Student_Class"/>
<one-to-many class="StudentEntity"/>
</bag>
</class>
</hibernate-mapping>

 

 

Spring.Net與NHibernate整合后的持久化操作如下:

 

       public class RepositoryBase < T >  : HibernateDaoSupport, IRepository < T >  where T : class 

    {
        #region IRepository<T> 成員

        public object Add(T entity)
        {
            return HibernateTemplate.Save(entity);
        }

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

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

        public T Get(int Id)
        {
            return HibernateTemplate.Get<T>(Id);
        }

        #endregion
    }

 

在Spring.Net中我們可以通過對RepositoryBase<T> 集成子HibernateDaoSupport進行注入。如上配置2中的

< object  id ="classRepository"  type ="DAO.Implement.RepositoryBase&lt;Domain.ClassEntity>,DAO" >
         < property  name ="HibernateTemplate"  ref ="HibernateTemplate" ></ property > </ object >

注意:在Spring.Net的配置中,對泛型類型中的"<"的配置是通過&lt;配置的,因為Spring.Net會認為"<" 是小於號。而對">"則沒有此類要求。

 

2、Spring.Net注入WCF 

上一篇中已經介紹了Spring.Net對WCF支持以及客戶端如何調用服務,本文不再做細致的介紹,只提幾點需要注意的地方:

View Code  

注意:service name="classService"  的配置中,name不再需要服務類的名稱,而是用Spring.Net對服務配置的id即可。

 

服務寄宿:

 

 static void Main(string[] args) 

{            
    ContextRegistry.GetContext();
    Console.WriteLine("Service Running...");
    Console.ReadLine();
}

  

3、Entity與DTO對象之間的轉化 

在NHibernate的應用中,一般是通過實體操作其映射的數據庫表。因此此實體為不可或缺的。但通過應用層的邏輯處理后,展示給UI的可能是從不同的表中獲取的信息,而UI層也不應用做一些業務處理;再者,如果將NHibernate使用的實體作為DTO也很可能面臨傳輸了大量UI不需要的信息。所以想通過NHibernate的實體作為DTO(Data Transmit Object)肯定不是一種理想的方式。這樣就面臨一個問題:NHibernate的 Entity與DTO對象間如何轉化? 
通過 Client傳輸過來的DTO對象給Entity對象賦值肯定可行,但是這種類似"體力活"的方式顯然不應該推崇。這里,我使用的是輕量、開源的AutoMapper。

Mapper.CreateMap<StudentDTO, StudentEntity>();

            Mapper.CreateMap < ClassDTO , ClassEntity >()
                .ForMember(item => item.Name, mapping => mapping.MapFrom(item => item.NO))
                .ForMember(item=>item.Students,mapping=>mapping.MapFrom(item=>item.StudentDtos);
            ClassEntity entity = Mapper.Map < ClassDTO , ClassEntity >(@class);
            return Manager.Add(entity);

 

 此外:通過還可以已通過Mapper.AssertConfigurationIsValid()來檢驗Entity與DTO之間映射是否正確。

 

 服務操作:

     

     public class ClassService : IContracts 

    {
        public IClassManager Manager { get; set; }

        #region IContracts 成員

        public object Add(ClassDTO @class)
        {
            Mapper.CreateMap<StudentDTO, StudentEntity>();
            Mapper.CreateMap<ClassDTO, ClassEntity>()
                .ForMember(item => item.Name, mapping => mapping.MapFrom(item => item.NO))
                .ForMember(item=>item.Students,mapping=>mapping.MapFrom(item=>item.StudentDtos);
            ClassEntity entity = Mapper.Map<ClassDTO, ClassEntity>(@class);
            return Manager.Add(entity);
        }

        #endregion
    }

 

同樣,我也是通過 對服務類中的Manager屬性進行注入,最終通過從IoC容器獲取Manager對象來進行對象的持久化操作。注入如下:

< object  id ="classService"  type ="Services.ClassService,Services" >
                 < property  name ="Manager"  ref ="classManager" ></ property >
</ object >

 

 客戶端調用:

 

IApplicationContext context = ContextRegistry.GetContext(); 
var proxy = context.GetObject( " classService "as IContracts;

var dto = new ClassDTO { NO = "035102A" };
List<StudentDTO> studentDtoList = new List<StudentDTO>()
                {
                    new StudentDTO{Name="StudentA",Sex=1},
                    new StudentDTO{Name="StudentB",Sex=0},
                };
dto.StudentDtos = studentDtoList;
proxy.Add(dto);
(proxy as ICommunicationObject).Abort():

 結果:

 

 

題外: 

不知道大家有沒有碰到過:有時調試程序時,添加的斷點有時會出現 "當前沒有命中斷點,還沒有為該文檔加載任何符號" 。下圖:

 在調試時可能出上述的調試過程中的問題:如下圖:

 

 我通過實踐發現,這是由於引用的此程序集(程序集A)的目標程序集(程序集B)中,可能由於生成時過程中,新生成程序集A沒有被拷貝到程序集B。導致這次問題的產生。若果程序集B所引用的為程序集A最新版本,則調試會是能正常進行的。如下圖:

 

 

 

 代碼下載:http://download.csdn.net/detail/tyb1222/4425673

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM