好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

三层架构+ASP.NET MVC 架构的快速搭建

三层架构+ASP.NET MVC 架构的快速搭建

上一篇博客中《 两天完成一个小型工程报价系统 》,许多朋友向我讨源码。其实我之后没发了,确实那种三层架构没什么意思,只是我个人的孤芳自赏,很多的处理都不是很成熟。所以我重新架构了一番,以一个小例子来阐述我的架构模式,当然,这和企业级的架构还是差距很大,不过,还是值得一读。不积硅步,无以至江海,只有从小细节慢慢领悟,步步为营,才能设计出优秀的企业级架构。

   重构后的架构图:

解决方案里项目设计:

数据库访问层接口设计:IBaseDao Repository模式

这儿使用了Repository模式,抽象出一个公共的接口IBaseDao,IBaseDao接口中定义了一系列契约(CRUD ),不管我的我数据访问用了那种技术,只要我实现了IBaseDao接口,则必须要实现接口定义的契约,所以接口的稳定至关重要,当然这样做的好处是显而易见的,减少了冗余代码。

   public   interface  IBaseDao<T>  where  T: class  
    {
        IList <T>  GetAllEntities();
          bool   SaveEntity(T entity);
          bool   UpdateEntity(T entity);
          bool   DeleteEntity(T entity);
          bool  DeleteEntityByID( object   id);
        T GetEntityByID(  object   id);
        IList <T> GetPageEntities( int  pageIndex,  int   PageSize);
    } 

首先ICustomerDao继承了IBaseDao接口:

  public interface  ICustomerDao<Customer>:IBaseDao

   public interface  ICustomerDao:IBaseDao<Customer>

    public   interface  ICustomerDao:IBaseDao<Customer> 
    {
    } 

 

OracleDao实现ICustomerDao接口:

  public   class   CustomerOracleDao:IDao.ICustomerDao
    {
          public  IList<Model.Customer>  GetAllEntities()
        {
              return  GetAllEntitiesBySqlWhere( ""  );

        }
          public  IList<Model.Customer> GetAllEntitiesBySqlWhere( string   sqlWhere)
        {

              string  sql =  string .Format( "  select * from Customer Where 1=1  {0}  "  ,sqlWhere);
            List <Customer> listCustomers =  new  List<Customer> ();
              using  (OracleDataReader odr = OracleHelper.ExecuteReader(OracleHelper.ConnectionString, System.Data.CommandType.Text, sql,  null  ))
            {
                  while   (odr.Read())
                {
                    Model.Customer customer  =  new   Customer();
                    customer.ID  = odr.GetInt32( 0  );
                    customer.Name  = odr.IsDBNull( 1 ) ?  ""  : odr.GetString( 1  );
                    customer.Phone  = odr.IsDBNull( 2 ) ?  ""  : odr.GetString( 2  );
                    customer.Remark  = odr.IsDBNull( 3 ) ?  ""  : odr.GetString( 3  );
                    listCustomers.Add(customer);

                }
            }
              return   listCustomers;
        }

          private   int   GetNewID()
        {
              string  sql =  "  select s_customer.nextval from dual  "  ;
              return   int .Parse(OracleHelper.ExecuteScalar(OracleHelper.ConnectionString, CommandType.Text, sql,  null  ).ToString());
        }

          public   bool   SaveEntity(Model.Customer entity)
        {
            entity.ID  =  GetNewID();
              bool  resultValue =  false  ;
              string  sql =  string .Format( @"  insert into Customer(ID,Name,Phone,Remark) values({0},'{1}','{2}','{3}')  "  ,entity.ID,entity.Name,entity.Phone,entity.Remark );
              if  (OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString, CommandType.Text, sql,  null ) >  0  )
            {
                resultValue  =  true  ;
            }
              return   resultValue;
           
        }

          public   bool   UpdateEntity(Model.Customer entity)
        {
              string  sql =  string .Format( "  update Customer set Name='{0}',Phone='{1}',Remark='{2}' where ID={3}  "  ,entity.Name,entity.Phone,entity.Remark,entity.ID);
              return  OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString, CommandType.Text, sql,  null ) >  0  ; 
        }

          public   bool   DeleteEntity(Model.Customer entity)
        {
              return   DeleteEntityByID(entity.ID);
        }

          public   bool  DeleteEntityByID( object   id)
        {
              string  sql =  string .Format( "  delete from Customer where ID={0}   "  ,id);
              return  OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString, CommandType.Text, sql,  null ) >  0  ;
        }

          public  Model.Customer GetEntityByID( object   id)
        {
              string  sqlWhere =  string .Format( "   and id={0}  "  , id);
              int  CID = ( int  )id;
            List <Model.Customer> list = GetAllEntitiesBySqlWhere(sqlWhere)  as  List<Customer> ;
              return  list.SingleOrDefault(c => c.ID ==  CID);
        }

          public  IList<Model.Customer> GetPageEntities( int  pageIndex,  int   PageSize)
        {
              throw   new   NotImplementedException();
        }
    } 

EFDao实现 ICustomerDao 接口:

  //  用EF来实现数据访问层接口 
     public   class   CustomerEFDao:ICustomerDao
    {
          //  上下文网关 
         private  Hotel.Model.HotelContainer hotelDB =  new   Model.HotelContainer();
          ///   <summary> 
         ///   获取全部用户信息
          ///   </summary> 
         ///   <returns></returns> 
         public  IList<Insigma.Hotel.Model.Customer>  GetAllEntities()
        {
              return  hotelDB.Customer.ToList<Customer> ();
        }

          public   bool   SaveEntity(Insigma.Hotel.Model.Customer entity)
        {
            hotelDB.Customer.AddObject(entity);
              bool  returnValue =  false  ;
              //  返回受影响的行数 
             if  (hotelDB.SaveChanges()> 0  )
            {
                returnValue  =  true  ;
            }
              return  returnValue;
         }
          ///   <summary> 
         ///   更新客户信息
          ///   </summary> 
         ///   <param name="entity"></param> 
         ///   <returns></returns> 
         public   bool   UpdateEntity(Insigma.Hotel.Model.Customer entity)
        {
              //  新的方法来保存
              //  hotelDB.Customer.Attach(entity);  //  附加到表对应集合缓冲中
              //  hotelDB.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified); 
             bool  resultValue =  false  ;
              //  if (hotelDB.SaveChanges()>0)
              //  {
              //      resultValue = true;
              //  }
              //  return resultValue; 
            HotelContainer hoteEntities =  new   HotelContainer();
              var  oldCustomer = ( from  c  in   hoteEntities.Customer
                                 where  c.ID ==  entity.ID
                                 select  c).SingleOrDefault<Customer> ();
            oldCustomer.Name  =  entity.Name;
            oldCustomer.Phone  =  entity.Phone;
            oldCustomer.Remark  =  entity.Remark;
              if  (hoteEntities.SaveChanges()> 0  )
            {
                resultValue  =  true  ;
            }
              return   resultValue;
        }
          ///   <summary> 
         ///   删除客户信息(一般是软删除)
          ///   </summary> 
         ///   <param name="entity"></param> 
         ///   <returns></returns> 
         public   bool   DeleteEntity(Insigma.Hotel.Model.Customer entity)
        {
              return   DeleteEntityByID(entity.ID);
        }
          ///   <summary> 
         ///   根据ID删除数据
          ///   </summary> 
         ///   <param name="id"></param> 
         ///   <returns></returns> 
         public   bool  DeleteEntityByID( object   id)
        {
             
             int  Id = ( int  )id;
              bool  resultValue =  false  ;
              var  deleteCustomer = hotelDB.Customer.Where<Customer>(c => c.ID == Id).SingleOrDefault<Customer> ();
              if  (deleteCustomer !=  null  )
            {
                hotelDB.Customer.DeleteObject(deleteCustomer);
                  if  (hotelDB.SaveChanges() >  0  )
                {
                    resultValue  =  true  ;
                }
            }
              return   resultValue;
        }
          ///   <summary> 
         ///  ///   </summary> 
         ///   <param name="id"></param> 
         ///   <returns></returns> 
         public  Insigma.Hotel.Model.Customer GetEntityByID( object   id)
        {
          
             int  Id = ( int  )id;
              return  hotelDB.Customer.Where<Customer>(c => c.ID == Id).SingleOrDefault<Customer> ();
        }

          public  IList<Insigma.Hotel.Model.Customer> GetPageEntities( int  pageIndex,  int   PageSize)
        {
          
             var  result = hotelDB.Customer.OrderBy(c =>c.ID).Skip<Customer>((pageIndex -  1 ) * PageSize).Take<Customer> (PageSize).ToList();
              return   result;
        }
    } 

SQLDao实现 ICustomerDao 接口:

 public   class   CustomerSQLDao:ICustomerDao
    {

          public  IList<Insigma.Hotel.Model.Customer>  GetAllEntities()
        {
              using  (CustomerTableAdapter adapter= new   CustomerTableAdapter ())
            {
                  var  result = ( from  c  in   adapter.GetData()
                               select   new  Customer { ID=c.ID,Name=c.Name,Phone=c.Phone}).ToList<Customer> ();
                  return   result;
            }
        }

          public   bool   SaveEntity(Insigma.Hotel.Model.Customer entity)
        {
              bool  resultValue= false  ;
              using  (CustomerTableAdapter adapter= new   CustomerTableAdapter ())
            {
                  if  (adapter.Insert(entity.Name, entity.Phone, entity.Remark) >  0  )
                {
                    resultValue  =  true  ;
                }
                  return   resultValue;
            }
        }

          public   bool   UpdateEntity(Insigma.Hotel.Model.Customer entity)
        {
              bool  resultValue =  false  ;
              using  (CustomerTableAdapter adapter= new   CustomerTableAdapter ())
            {
                  if  (adapter.UpdateCustomer(entity.Name,entity.Phone,entity.Remark,entity.ID)> 0  )
                {
                    resultValue  =  true  ;
                }
                  return   resultValue;
            }
        }

          public   bool   DeleteEntity(Insigma.Hotel.Model.Customer entity)
        {
              return   DeleteEntityByID(entity.ID);
        }

          public   bool  DeleteEntityByID( object   id)
        {
              bool  resultValue =  false  ;
              int  CID=( int  )id;
              using  (CustomerTableAdapter adapter= new   CustomerTableAdapter ())
            {
                  //  若取名Delete会变成Delete1 
                 if  (adapter.DeleteCustomerByID(CID)> 0  )
                {
                    resultValue  =  true  ;
                }
                  return   resultValue;
            }
        }

          public  Insigma.Hotel.Model.Customer GetEntityByID( object   id)
        {
              using  (CustomerTableAdapter adapter= new   CustomerTableAdapter ())
            {
                  var  table= adapter.GetCustomerByID(Convert.ToInt32(id));
                Customer customer  =  new   Customer();
                customer.ID  = table[ 0  ].ID;
                customer.Name  = table[ 0  ].Name;
                customer.Phone  = table[ 0  ].Phone;
                  return   customer;

            }
        }

          public  IList<Insigma.Hotel.Model.Customer> GetPageEntities( int  pageIndex,  int   PageSize)
        {
              using  (CustomerTableAdapter adapter= new   CustomerTableAdapter ())
            {
                  var  result = ( from  c  in   adapter.GetData()
                                select   new  Customer { ID = c.ID, Name = c.Name, Phone = c.Phone }).OrderBy(c => c.ID).Skip<Customer>((pageIndex -  1 ) * PageSize).Take<Customer>(PageSize).ToList<Customer> ();
                  return   result;
            }
        }
    } 

这样我们就设计好了数据访问层实现方式,一共有三层方法来实现对数据库的访问,但是不管是OracleDao,还是EFDao,SQLDao实现了IBaseDao接口。这就是 Repository模式。

业务逻辑层接口设计:IBLL

 

  public   interface   ICustomerService
    {
          //  Controller来调用业务逻辑 
        IList<Customer>  GetAllCustomers();
          bool   SaveCustomer(Customer customer);
          bool   UpdateCustomer(Customer customer);
          bool  DeleteCustomer( int   id);
        IList <Customer> GetPageCustomers( int  pageIndex,  int   pageSize);
        Customer GetCustomerByID(  int   id);
    } 

这儿我们更希望通过配置文件的方式手动的去选择需要的数据访问层技术。所以这儿可以运用 抽象工厂+反射 的技术,当然还有 IOC依赖注入

  public   class   CustomerService:ICustomerService
    {
          public   CustomerService()
        {
              //  最好通过抽象工厂和反射 IOC依赖注入
              //  this.customerDao = new EFDao.CustomerEFDao(); 
             this .customerDao =  DaoFactory.GetCustomerDao();
        }
          ///   <summary> 
         ///   数据表数据访问层接口(好处:接口是稳定)
          ///   </summary> 
         private   ICustomerDao customerDao;

          public   ICustomerDao CustomerDao
        {
              get  {  return   customerDao; }
              set  { customerDao =  value; }
        }
          public  IList<Model.Customer>  GetAllCustomers()
        {
              return   CustomerDao.GetAllEntities();
        }

          public   bool   SaveCustomer(Model.Customer customer)
        {
              return   CustomerDao.SaveEntity(customer);
        }

          public   bool   UpdateCustomer(Model.Customer customer)
        {
              return   CustomerDao.UpdateEntity(customer);
        }

          public   bool  DeleteCustomer( int   id)
        {
              return   CustomerDao.DeleteEntityByID(id);
        }

          public  IList<Model.Customer> GetPageCustomers( int  pageIndex,  int   pageSize)
        {
              return   CustomerDao.GetPageEntities(pageIndex, pageSize);
        }

          public  Model.Customer GetCustomerByID( int   id)
        {
              return   CustomerDao.GetEntityByID(id);
        }
    } 

抽象共厂的实现,因为反射出实例很耗费性能,所以运用了 缓存 来减轻负担:

 public   class   DaoCache
    {
          public   DaoCache()
        {

        }
          public   static   object  GetDao( string   key)
        {
            System.Web.Caching.Cache daoCache  =  HttpRuntime.Cache;
              return   daoCache.Get(key);
        }
          public   static   void  InsertDaoCache( string  key,  object   value)
        {
              if  (GetDao(key) ==  null  )
            {
                System.Web.Caching.Cache daoCache  =  HttpRuntime.Cache;
                daoCache.Insert(key, value);
            }
        }
    } 

抽象工厂反射实例:

  public   class   DaoFactory
    {
         public   static   readonly   string  DaoPath=System.Configuration.ConfigurationManager.AppSettings[ "  DaoPath  "  ];
          public   static   readonly   string  DaoHZ=System.Configuration.ConfigurationManager.AppSettings[ "  HZ  "  ];
          public   static   object  CreateDao( string  assemblyPath,  string   objType)
        {
              var  cacheDao =  DaoCache.GetDao(objType);
              if  (cacheDao== null  )
            {
                cacheDao  =  Assembly.Load(assemblyPath).CreateInstance(objType);
                DaoCache.InsertDaoCache(objType, cacheDao);
            }
              return   cacheDao;
        }
          public   static   ICustomerDao GetCustomerDao()
        {
              return  CreateDao(DaoPath,  string .Format( "  {0}.Customer{1}  " , DaoPath, DaoHZ))  as   ICustomerDao;
        }
    } 

这样,最简单的业务逻辑层完成了,当然这儿很复杂,还需要用到 Facade模式。

表示层(MVC)

 

表示层当然是指挥家Controller去访问业务逻辑层,把数据装配到Model中,交给View来显示。

  public   class   CustomerController : Controller
    {
         //   private HotelContainer db = new HotelContainer(); 
         private  Insigma.Hotel.IBLL.ICustomerService customerService = new   BLL.CustomerService();
          // 
         //   GET: /Customer/ 

         public   ViewResult Index()
        {
              return   View(customerService.GetAllCustomers());
        }

          // 
         //   GET: /Customer/Details/5 

         public  ViewResult Details( int   id)
        {
            Customer customer  =  customerService.GetCustomerByID(id);
              return   View(customer);
        }

          // 
         //   GET: /Customer/Create 

         public   ActionResult Create()
        {
              return   View();
        } 

          // 
         //   POST: /Customer/Create 
 
        [HttpPost]
          public   ActionResult Create(Customer customer)
        {
              if   (ModelState.IsValid)
            {
                customerService.SaveCustomer(customer);
                  return  RedirectToAction( "  Index  "  );  
            }

              return   View(customer);
        }
        
          // 
         //   GET: /Customer/Edit/5 
 
         public  ActionResult Edit( int   id)
        {
            Customer customer  =  customerService.GetCustomerByID(id);
              return   View(customer);
        }

          // 
         //   POST: /Customer/Edit/5 
 
        [HttpPost]
          public   ActionResult Edit(Customer customer)
        {
              if   (ModelState.IsValid)
            {
                customerService.UpdateCustomer(customer);
                  return  RedirectToAction( "  Index  "  );
            }
              return   View(customer);
        }

          // 
         //   GET: /Customer/Delete/5 
 
         public  ActionResult Delete( int   id)
        {
            Customer customer  =  customerService.GetCustomerByID(id);
              return   View(customer);
        }

          // 
         //   POST: /Customer/Delete/5 
 
        [HttpPost, ActionName(  "  Delete  "  )]
          public  ActionResult DeleteConfirmed( int   id)
        {
            customerService.DeleteCustomer(id);
              return  RedirectToAction( "  Index  "  );
        }

          protected   override   void  Dispose( bool   disposing)
        {
      
        }
    } 

现在只需要修改配置文件就可以灵活的选择OracleDao、EFDao、SQLDao,而我们的项目丝毫不会有任何改动:

    <add key= "  DaoPath  "  value= "  Insigma.Hotel.EFDao  "  />
    <add key= "  HZ  "  value= "  EFDao  "  />

 

总结:

这是对稍早那篇文章的总结,接口引入稳定了开发。反射的引用让程序员更加关注业务层,提高了开发效率。

 

牛人的架构设计图:来自 刘冬.NET

 

 

 

 

分类:  ASP.NET MVC ,  架构思想

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于三层架构+ASP.NET MVC 架构的快速搭建的详细内容...

  阅读:49次