在企业级应用开发中,利用合适的框架针对不同项目构建相应的应用。Spring.Net作为Spring的.Net版本,具有很强大的应用。如:作为IoC容器、AOP处理框架、与NHibernate的集成、Spring.Net发布WebService\WCF服务等。而NHibernate作为一个优秀的ORM框架也广受开发者的青睐。本文将通过Spring.Net+NHibernate来构建WCF应用。
先上一张结构图:
正式介绍之前介绍一下框架 版本:
Spring.Net :1.3.2
NHibernate :3.2(目前Spring支持的NHibernate最高版本)
1、Spring.Net与NHibernate的集成应用
Spring.Net以及NHibernate的配置:
Spring.Net对NHibernate支持的配置(配置1):
< 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):

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):
Spring.Net与NHibernate整合后的持久化操作如下:
{
#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中的
< property name ="HibernateTemplate" ref ="HibernateTemplate" ></ property > </ object >
注意:在Spring.Net的配置中,对泛型类型中的"<"的配置是通过<配置的,因为Spring.Net会认为"<" 是小于号。而对">"则没有此类要求。
2、Spring.Net注入WCF
上一篇中已经介绍了Spring.Net对WCF支持以及客户端如何调用服务,本文不再做细致的介绍,只提几点需要注意的地方:
View Code
注意:service name="classService" 的配置中,name不再需要服务类的名称,而是用Spring.Net对服务配置的id即可。
服务寄宿:
{
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>();
.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 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对象来进行对象的持久化操作。注入如下:
< property name ="Manager" ref ="classManager" ></ property >
</ object >
客户端调用:
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