• 使用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

  • 相关阅读:
    450. 删除二叉搜索树中的节点
    958. 二叉树的完全性检验
    5211. 概率最大的路径(197)
    5447. 石子游戏 IV
    174. 地下城游戏
    Codeforces Round #622 (Div. 2).C2
    Codeforces Round #624 (Div. 3) F. Moving Points 题解
    竞赛头
    离散化
    线段树
  • 原文地址:https://www.cnblogs.com/tyb1222/p/2588742.html
Copyright © 2020-2023  润新知