Asp.net MVC 2 + Castle + NHibernate 项目实战(1)

简介: 本文将开始一步一步地使用Asp.net MVC 2 + Castle + NHibernate 开发一个项目。   在开始之前,我先对这三个组件做一个简单的介绍:  Asp.net MVC  它是微软提供的一个基于MVC标准的Web开发模式,其典型特点是有控制器和视图;在这之前,.NET下的Web开发模式大多是采用WebForm,其典型特点是服务端控件和后台触发事件;   NHibernate 它是一个ORM框架,使用Java的SSH做过项目开发的人就非常熟悉了,当前最新版本为NHibernate 3.0,听说完全支持Linq查询语句了,以前只支持HQL语句。

本文将开始一步一步地使用Asp.net MVC 2 + Castle + NHibernate 开发一个项目。

 

在开始之前,我先对这三个组件做一个简单的介绍:

 Asp.net MVC 

它是微软提供的一个基于MVC标准的Web开发模式,其典型特点是有控制器和视图;在这之前,.NET下的Web开发模式大多是采用WebForm,其典型特点是服务端控件和后台触发事件; 

 NHibernate

它是一个ORM框架,使用Java的SSH做过项目开发的人就非常熟悉了,当前最新版本为NHibernate 3.0,听说完全支持Linq查询语句了,以前只支持HQL语句。 

 Castle

它是一个非常大的框架,包含IoC、MVC、ORM、AOP等,这次我只用到其IoC的功能。

 

关于IoC

IoC的英文是Inversion of Control,中文意思是控制反转,也有称其为Dependence Injection,中文意思是依赖注入,也就是DI;

除了Castle可以作IoC 外,还有著名的Spring.Net、Unity等,在我另外一个开源博客项目 http://rorowo.codeplex.com/ 中就用到了微软的Unity 2.0作为IoC。

 

好了,废话不多说,下面开始。 

 

首先,第一步是创建一个解决方案,项目结构如下:

 

需要引用的DLL库文件,我们全部放在RoRoWo.Common.DependLib下:

 

 根据表的结构,如图: 

 

 

现在我们开始为表结构创建实体类,以BlogCategory表为例,我们根据该表的字段名称和数据类型创建一个POCO类,放在RoRoWo.Domain.Entities下,代码内容如下:

 img_405b18b4b6584ae338e0f6ecaf736533.gif代码

namespace  RoRoWo.Domain {
    
    
public   class  Blogcategory {
        
public  Blogcategory() { }
        
public   virtual   int  Cateid {  get set ; }
        
public   virtual  IList < Blogarticle >  Blogarticles {  get set ; }
        
public   virtual   string  Catename {  get set ; }
        
public   virtual   int  Parentid {  get set ; }
        
public   virtual   int  State {  get set ; }
        
public   virtual   int  Sortid {  get set ; }
        
public   virtual   int  Articlecount {  get set ; }
        
public   virtual  System.DateTime Createtime {  get set ; }
        
public   virtual   string  Note {  get set ; }
    }
}

 

 在这里,我推荐一个可以生成NHibernate映射对象代码的工具(开源的),项目地址:NHibernate Mapping Generator(它同时支持 hbm.xml文件的方式、Fluent Mapping方式、Castle ActiveRecord方式)

接下来,要为这个类创建一个映射关系,我这里使用配置文件的方式,但是正式项目推荐使用Fluent方式。我们创建一个XML文件,文件名为“Blogcategory.hbm.xml”,放在RoRoWo.Domain.Mappings下,内容如下:

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
<? xml version = " 1.0 "  encoding = " utf-8 " ?>
< hibernate - mapping assembly = " RoRoWo.Domain "   namespace = " RoRoWo.Domain "  xmlns = " urn:nhibernate-mapping-2.2 "   default - lazy = " false " >
    
< class  name = " Blogcategory "  table = " BlogCategory " >
        
< id name = " Cateid "  column = " CateID " >
            
< generator  class = " native "   />
        
</ id >
        
< property name = " Catename "  column = " CateName "   />
        
< property name = " Parentid "  column = " ParentID "   />
        
< property name = " State "  column = " State "   />
        
< property name = " Sortid "  column = " SortID "   />
        
< property name = " Articlecount "  column = " ArticleCount "   />
        
< property name = " Createtime "  column = " CreateTime "   />
        
< property name = " Note "  column = " Note "   />
    
</ class >
</ hibernate - mapping >

 

 

这里就是一个典型的映射关系了,如果有一对多,多对多的表关系,也是在这个配置中进行维护。

创建这个XML后,还有个很重要的操作,就是将其设为“嵌入的资源” ,鼠标右键查看“Blogcategory.hbm.xml”文件属性,将“生成操作”项的“内容”改为“嵌入的资源”,如图:

 

 到此,一个映射关系的实体就建立好了,下面我们就要来实现NHibernate对该表的增删改查操作了,我们把这些操作的实现放在RoRoWo.Data中。

注意,RoRoWo.Data需要添加对 “Castle.Core.dll”  " Castle.DynamicProxy2.dll "   " NHibernate.dll "   " RoRoWo.Domain "  的引用。

 

在创建数据库操作类之前,我们需要创建一个 “SessionManager”类,它负责维护整个ORM中的上下文,这里我使用李永京的一个类,其代码如下:

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

using  NHibernate;
using  NHibernate.Cfg;

namespace  RoRoWo.Data
{
    
public   class  SessionManager
    {
        
private  ISessionFactory _sessionFactory;
        
public  SessionManager()
        {
            _sessionFactory  =  GetSessionFactory();
        }
        
private  ISessionFactory GetSessionFactory()
        {
            
return  ( new  Configuration()).Configure().BuildSessionFactory();
        }
        
public  ISession GetSession()
        {
            
return  _sessionFactory.OpenSession();
        }
    }
}

 

 

我们创建一个“BlogCategoryRespository.cs”文件,其代码如下:

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

using  NHibernate;
using  NHibernate.Cfg;
using  NHibernate.Criterion;
using  RoRoWo.Domain;

namespace  RoRoWo.Data
{
    
public   class  BlogCategoryRespository
    {
        
private  ISession _session;
        
public  ISession Session
        {
            
set
            {
                _session  =  value;
            }
        }

        
public  BlogCategoryRespository(ISession session)
        {
            _session  =  session;
        }

        
public  Blogcategory GetById( int  cateId)
        {

            
return  _session.Get < Blogcategory > (cateId);
        }

        
public   void  Create(Blogcategory dto)
        {
            _session.Save(dto);
            _session.Flush();
        }

        
public   int  CreateAndReturn(Blogcategory dto)
        {
            
int  newid  =  ( int )_session.Save(dto);
            _session.Flush();
            
return  newid;
        }

        
///   <summary>
        
///  使用事务
        
///   </summary>
        
///   <param name="dto"></param>
        
///   <returns></returns>
         public   int  CreateTransaction(Blogcategory dto)
        {
            
using  (ITransaction tx  =  _session.BeginTransaction())
            {
                
try
                {
                    
int  newId  =  ( int )_session.Save(dto);
                    _session.Flush();
                    tx.Commit();
                    
return  newId;
                }
                
catch  (HibernateException)
                {
                    tx.Rollback();
                    
throw ;
                }
            }
        }

        
public   void  UpdateCustomer(Blogcategory dto)
        {
            _session.Update(dto);
            _session.Flush();
        }

        
public   void  SaveOrUpdate(IList < Blogcategory >  dtos)
        {
            
foreach  (var c  in  dtos)
            {
                _session.SaveOrUpdate(c);
            }
            _session.Flush();
        }

        
public   void  Delete(Blogcategory dto)
        {
            _session.Delete(dto);
            _session.Flush();
        }

        
public  IList < Blogcategory >  From()
        {
            
// 返回所有Blogcategory类的实例
             return  _session.CreateQuery( " from Blogcategory " )
                .List < Blogcategory > ();
        }

        
public  IList < int >  Select()
        {
            
// 返回所有Blogcategory的CateId
             return  _session.CreateQuery( " select c.CateId from Blogcategory c " )
                .List < int > ();
        }

        
public  IList < Blogcategory >  Where()
        {
            
return  _session.CreateQuery( " from Blogcategory c where c.CateId='3' " )
                .List < Blogcategory > ();
        }

        
public  IList < Blogcategory >  GetGreaterThan( int  CateId)
        {
            
// return _session.CreateQuery("select from Blogcategory c where c.CateId > :cid")
            
//     .SetInt32("cid", CateId)
            
//     .List<Blogcategory>();

            
return  _session.CreateCriteria( typeof (Blogcategory))
            .Add(Restrictions.Gt( " CateId " , CateId))
            .List < Blogcategory > ();

        }

        
public  IList < Blogcategory >  CreateCriteria()
        {
            ICriteria crit  =  _session.CreateCriteria( typeof (Blogcategory));
            crit.SetMaxResults( 50 );
            IList < Blogcategory >  blogcategorys  =  crit.List < Blogcategory > ();
            
return  blogcategorys;
        }

        
public  IList < Blogcategory >  Narrowing()
        {
            IList < Blogcategory >  blogcategorys  =  _session.CreateCriteria( typeof (Blogcategory))
                .Add(Restrictions.Like( " Catename " " s% " ))
                .Add(Restrictions.Between( " Parentid " " 1 " " 3 " ))
                .List < Blogcategory > ();
            
return  blogcategorys;
        }

        
public  IList < Blogcategory >  Query()
        {
            Blogcategory dtoSample  =   new  Blogcategory() { Catename  =   " sss " , Parentid  =   0  };
            
return  _session.CreateCriteria( typeof (Blogcategory))
                .Add(Example.Create(dtoSample))
                .List < Blogcategory > ();
        }

        
public  IList < Blogcategory >  UseQueryByExample_Get(Blogcategory dtoSample)
        {
            Example example  =  Example.Create(dtoSample)
                .IgnoreCase()
                .EnableLike()
                .SetEscapeCharacter( ' & ' );
            
return  _session.CreateCriteria( typeof (Blogcategory))
               .Add(example)
               .List < Blogcategory > ();
        }

    }
}

 

 

该代码具有了对一个表的基本操作,现在我们就来创建一个单元测试,测试一下插入数据。

在创建插入操作时,我们要能使NHibernate正常工作,还需要创建一个配置文件,我们创建一个XML文件,文件名为“hibernate.cfg.xml”,放在RoRoWo.UnitTest下,其内容为:

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
<? xml version="1.0" encoding="utf-8" ?>
< hibernate-configuration   xmlns ="urn:nhibernate-configuration-2.2"   >
    
< session-factory >
        
< property  name ="connection.driver_class" > NHibernate.Driver.SqlClientDriver </ property >
        
< property  name ="connection.connection_string" >
            Data Source=.;Initial Catalog=RoRoWoDB;User ID=sa;Password=2010;
        
</ property >
        
< property  name ="adonet.batch_size" > 10 </ property >
        
< property  name ="show_sql" > true </ property >
        
< property  name ="dialect" > NHibernate.Dialect.MsSql2005Dialect </ property >
        
< property  name ="use_outer_join" > true </ property >
        
< property  name ="command_timeout" > 10 </ property >
        
< property  name ="query.substitutions" > true 1, false 0, yes 'Y', no 'N' </ property >
        
< property  name ="proxyfactory.factory_class" >
            NHibernate.ByteCode.Castle.ProxyFactoryFactory,
            NHibernate.ByteCode.Castle
        
</ property >
        
< mapping  assembly ="RoRoWo.Domain" />
    
</ session-factory >
</ hibernate-configuration >

 

 其中“Data Source=.;Initial Catalog=RoRoWoDB;User ID=sa;Password=2010;”是我的数据库连接,您可以改为您的。

 

现在我们添加一个单元测试(不明白如何添加的请参考相关资料),先测试插入方法,其代码如下:

 img_405b18b4b6584ae338e0f6ecaf736533.gif代码

         ///   <summary>
        
/// Create 的测试
        
/// </summary>
        [TestMethod()]
        
public   void  CreateTest()
        {
            SessionManager sessionManager  =   new  SessionManager();
            ISession session  =  sessionManager.GetSession();
            BlogCategoryRespository target  =   new  BlogCategoryRespository(session);
            Blogcategory dto  =   new  Blogcategory();

            dto.Catename  =   " 新分类 "   +   new  Random().Next( 100000 999999 ).ToString();
            dto.Parentid  =   0 ;
            dto.State  =   0 ;
            dto.Createtime  =  DateTime.Now;

            
int  newid  =  target.CreateAndReturn(dto);
            Assert.IsTrue(newid  >   0 );
        }

 

 执行单元测试,可以通过测试,并且在数据库中已经成功插入了一条记录,结果完全正确;

我们接着对查询方法进行测试,我们将测试代码如下:

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
         ///   <summary>
        
/// GetById 的测试
        
/// </summary>
        [TestMethod()]
        
public   void  GetByIdTest()
        {
            SessionManager sessionManager  =   new  SessionManager();
            ISession session  =  sessionManager.GetSession();
            BlogCategoryRespository target  =   new  BlogCategoryRespository(session);
            
int  cateId  =   3 ;
            Blogcategory actual;
            actual  =  target.GetById(cateId);
            Assert.AreEqual(cateId, actual.Cateid);

        }

        
///   <summary>
        
/// From 的测试
        
/// </summary>
        [TestMethod()]
        
public   void  FromTest()
        {
            SessionManager sessionManager  =   new  SessionManager();
            ISession session  =  sessionManager.GetSession();
            BlogCategoryRespository target  =   new  BlogCategoryRespository(session);
            IList < Blogcategory >  actual;
            actual  =  target.From();
            Assert.IsTrue(actual.Count  >   0 );

        }

        
///   <summary>
        
/// Select 的测试
        
/// </summary>
        [TestMethod()]
        
public   void  SelectTest()
        {
            SessionManager sessionManager  =   new  SessionManager();
            ISession session  =  sessionManager.GetSession();
            BlogCategoryRespository target  =   new  BlogCategoryRespository(session);
            IList < int >  actual;
            actual  =  target.Select();
            Assert.IsTrue(actual.Count  >   0 );
        }

        
///   <summary>
        
/// Where 的测试
        
/// </summary>
        [TestMethod()]
        
public   void  WhereTest()
        {
            SessionManager sessionManager  =   new  SessionManager();
            ISession session  =  sessionManager.GetSession();
            BlogCategoryRespository target  =   new  BlogCategoryRespository(session);

            IList < Blogcategory >  actual;
            actual  =  target.Where();
            Assert.IsTrue(actual.Count  >   0 );
        }

        
///   <summary>
        
/// GetGreaterThan 的测试
        
/// </summary>
        [TestMethod()]
        
public   void  GetGreaterThanTest()
        {
            SessionManager sessionManager  =   new  SessionManager();
            ISession session  =  sessionManager.GetSession();
            BlogCategoryRespository target  =   new  BlogCategoryRespository(session);
            
int  CateId  =   0 //  TODO: 初始化为适当的值
            IList < Blogcategory >  actual;
            actual  =  target.GetGreaterThan(CateId);
            Assert.IsTrue(actual.Count  >   0 );

        }

 

 

 测试结果全部绿灯通过:

 

下一篇,我将谈谈如何配置一对多和多对多的表映射关系。

 

该例子的完整代码可以到开源平台下载,地址: http://rorowoproject.codeplex.com

文章中如有不足之处,望大家多指正。

 

 

 

目录
相关文章
|
前端开发 .NET SoC
|
前端开发 .NET 开发者
《精通 ASP.NET MVC 3 框架(第三版)》----1.4 谁该使用ASP.NET MVC
如同任何新技术一样,因为其存在就必须使用它,这并不是一个充分的理由。在以下小节中,我们将给出MVC框架与大多数流行的替代品比较所得到的我们的观点。作为编写一本关于MVC框架书籍的人,我们两人尽可能做到没有偏见,但我们知道,这受限于我们的客观情况。
1526 0
|
JavaScript 前端开发 .NET
《精通 ASP.NET MVC 3 框架(第三版)》----1.5 ASP.NET MVC 3的新特性
MVC 3版的主要特性是引入了Razor视图引擎。以前的MVC版本一直依赖于ASP.NET的视图引擎,它依赖于ASP.NET的<%和%>代码块(如果你曾做过任意一种ASP.NET开发,你肯定看到过它的使用)。
1398 0
|
SQL 前端开发 .NET
asp.net mvc 项目架构解析
请先看框架图: 从上图可知: 1、Controller控制器只是充当了管道的作用。只做任务的分发,不做请求中的具体业务处理。 2、Views视图充当了展示数据的作用。不做任何取数逻辑的处理,只是展示逻辑的处理。
1263 0
|
前端开发 .NET 开发框架
解读ASP.NET 5 & MVC6系列(17):MVC中的其他新特性
原文:解读ASP.NET 5 & MVC6系列(17):MVC中的其他新特性 (GlobalImport全局导入功能) 默认新建立的MVC程序中,在Views目录下,新增加了一个_GlobalImport.cshtml文件和_ViewStart.cshtml平级,该文件的功能类似于之前Views目录下的web.config文件,之前我们在该文件中经常设置全局导入的命名空间,以避免在每个view文件中重复使用@using xx.xx语句。
1061 0