• 多层架构+MVC+EF+AUTOFAC+AUTOMAPPER【转】


    多层架构+MVC+EF+AUTOFAC+AUTOMAPPER

    最近使用ligerui搭建了一个简单的教务管理demo,将重要的地方记录,也希望能帮到有这方面需要园友。


    一、目录

     1、多层架构+MVC+EF+AUTOFAC+AUTOMAPPER;

     2、MVC中验证码的实现(经常用,记录备用)

    二、正文

     多层架构中等以上规模以上的系统用得比较多,此demo功能不多,出于抱着学习的态度搭建了一个多层架构,并加入现在很流行的依赖倒转(autofac)、对象映射工具(automapper)。

     话说没图你说个J8,先上框架图:

      Model层中Entity存放数据库实体,使用code first,ViewModel存放界面展示模型。DAL层中IDAO存放接口,EFDAO 实现IDAO。BLL结构与DAL类似,接口+实现。WEB层就是我们的UI层了,在这个框架中,WEB层使用MVC。什么,MVC不就是多层架构嘛,怎 么还把它放Web层呢?MVC并不等同于多层架构,有这样疑问的同学,请在园内搜索相关文章。Infrastructure层是我们的基础设施层,我把一 些常用的工具类封装后放入其中,方便其它地方调用。

      IDao中定义了一个公共基类,基类中定义所有子类都会用到的查询方法:

     1 namespace YTJWGL_IDao
     2 {
     3     public interface IBaseDao<T>
     4     {
     5         #region 查询普通实现方案(基于Lambda表达式的Where查询)
     6         /// <summary>
     7         /// 获取所有Entity
     8         /// </summary>
     9         /// <param name="exp">Lambda条件的where</param>
    10         /// <returns></returns>
    11         IEnumerable<T> GetEntities(Func<T, bool> exp);
    12 
    13         /// <summary>
    14         /// 计算总个数(分页)
    15         /// </summary>
    16         /// <param name="exp">Lambda条件的where</param>
    17         /// <returns></returns>
    18         int GetEntitiesCount(Func<T, bool> exp);
    19 
    20         /// <summary>
    21         /// 分页查询(Linq分页方式)
    22         /// </summary>
    23         /// <param name="pageNumber">当前页</param>
    24         /// <param name="pageSize">页码</param>
    25         /// <param name="orderName">lambda排序名称</param>
    26         /// <param name="sortOrder">排序(升序or降序)</param>
    27         /// <param name="exp">lambda查询条件where</param>
    28         /// <returns></returns>
    29         IEnumerable<T> GetEntitiesForPaging(int pageNumber, int pageSize, Func<T, string> orderName, string sortOrder, Func<T, bool> exp);
    30 
    31         /// <summary>
    32         /// 根据条件查找
    33         /// </summary>
    34         /// <param name="exp">lambda查询条件where</param>
    35         /// <returns></returns>
    36         T GetEntity(Func<T, bool> exp);
    37 
    38         #endregion
    39 
    40         //#endregion
    41         /// <summary>
    42         /// 插入Entity
    43         /// </summary>
    44         /// <param name="model"></param>
    45         /// <returns></returns>
    46         bool Insert(T entity);
    47         /// <summary>
    48         /// 更新Entity
    49         /// </summary>
    50         /// <param name="model"></param>
    51         /// <returns></returns>
    52         bool Update(T entity);
    53         /// <summary>
    54         /// 删除Entity
    55         /// </summary>
    56         /// <param name="entity"></param>
    57         /// <returns></returns>
    58         bool Delete(T entity);
    59         /// <summary>
    60         /// 删除实现 存储过程实现方式(调用spDelete+表名+ 主键ID)
    61         /// </summary>
    62         /// <param name="ID">删除的主键</param>
    63         /// <returns></returns>
    64         //bool Delete(object ID);
    65     }
    66 }
     

    IDAO

      EFDao有一个类实现这一公共基类:

     1 namespace YTJWGL_EFDao
      2 {
      3     public class BaseEFDao<T> : IBaseDao<T> where T : class,new()//限制T的类型为class或者对象
      4     {
      5 
      6 
      7         #region 查询普通实现方案(基于Lambda表达式的Where查询)
      8         /// <summary>
      9         /// 获取所有Entity
     10         /// </summary>
     11         /// <param name="exp">Lambda条件的where</param>
     12         /// <returns>返回IEnumerable类型</returns>
     13         public virtual IEnumerable<T> GetEntities(Func<T, bool> exp)
     14         {
     15             using (Entities db = new Entities())
     16             {
     17                 return db.Set<T>().Where(exp).ToList();
     18             }
     19 
     20 
     21         }
     22         /// <summary>
     23         /// 计算总个数(分页)
     24         /// </summary>
     25         /// <param name="exp">Lambda条件的where</param>
     26         /// <returns></returns>
     27         public virtual int GetEntitiesCount(Func<T, bool> exp)
     28         {
     29             using (Entities db = new Entities())
     30             {
     31                 return db.Set<T>().Where(exp).ToList().Count();
     32 
     33             }
     34         }
     35         /// <summary>
     36         /// 分页查询(Linq分页方式)
     37         /// </summary>
     38         /// <param name="pageNumber">当前页</param>
     39         /// <param name="pageSize">页码</param>
     40         /// <param name="orderName">lambda排序名称</param>
     41         /// <param name="sortOrder">排序(升序or降序)</param>
     42         /// <param name="exp">lambda查询条件where</param>
     43         /// <returns></returns>
     44         public virtual IEnumerable<T> GetEntitiesForPaging(int pageNumber, int pageSize, Func<T, string> orderName, string sortOrder, Func<T, bool> exp)
     45         {
     46             using (Entities db = new Entities())
     47             {
     48                 if (sortOrder == "asc") //升序排列
     49                 {
     50                     return db.Set<T>().Where(exp).OrderBy(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
     51                 }
     52                 else
     53                 {
     54                     return db.Set<T>().Where(exp).OrderByDescending(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
     55                 }
     56             }
     57 
     58         }
     59         /// <summary>
     60         /// 根据条件查找满足条件的一个entites
     61         /// </summary>
     62         /// <param name="exp">lambda查询条件where</param>
     63         /// <returns></returns>
     64         public virtual T GetEntity(Func<T, bool> exp)
     65         {
     66             using (Entities db = new Entities())
     67             {
     68                 return db.Set<T>().Where(exp).SingleOrDefault();
     69             }
     70         }
     71         #endregion
     72 
     73         #region 增改删实现
     74         /// <summary>
     75         /// 插入Entity
     76         /// </summary>
     77         /// <param name="model"></param>
     78         /// <returns></returns>
     79         public virtual bool Insert(T entity)
     80         {
     81             using (Entities db = new Entities())
     82             {
     83                 var obj = db.Set<T>();
     84                 obj.Add(entity);
     85                 return db.SaveChanges() > 0;
     86 
     87             }
     88 
     89         }
     90         /// <summary>
     91         /// 更新Entity(注意这里使用的傻瓜式更新,可能性能略低)
     92         /// </summary>
     93         /// <param name="model"></param>
     94         /// <returns></returns>
     95         public virtual bool Update(T entity)
     96         {
     97             using (Entities db = new Entities())
     98             {
     99                 var obj = db.Set<T>();
    100                 obj.Attach(entity);
    101                 db.Entry(entity).State = System.Data.EntityState.Modified;
    102                 return db.SaveChanges() > 0;
    103             }
    104 
    105 
    106         }
    107         /// <summary>
    108         /// 删除Entity
    109         /// </summary>
    110         /// <param name="entity"></param>
    111         /// <returns></returns>
    112         public virtual bool Delete(T entity)
    113         {
    114             using (Entities db = new Entities())
    115             {
    116                 var obj = db.Set<T>();
    117                 if (entity != null)
    118                 {
    119                     obj.Attach(entity);
    120                     db.Entry(entity).State = System.Data.EntityState.Deleted;
    121                     obj.Remove(entity);
    122                     return db.SaveChanges() > 0;
    123                 }
    124                 return false;
    125             }
    126 
    127         }
    128         #endregion
    129     }
    130 }

    EFDAO

      可以看到,代码中都是使用的泛型。根据传入的实体类型决定访问莫一数据实体。

      倘若,我们有一个数据实体类叫做Admin,IDAO,EFDAO中可以分别添加Admin对应的DAL层文件: 

    IAdminDao

    1 namespace YTJWGL_EFDao
    2 {
    3     public class AdminEFDao : BaseEFDao<YTJWGL_Admin>, IAdminDao<YTJWGL_Admin>
    4     {
    5     }
    6 }
    AdminEFDao

       IAdminDao继承我们上面定义的 公共接口,AdminEFDao继承IAdminDao接口以及BaseEFDao基类,这样我们可以在IAdminDao中定义该数据实体特有的查询方 法,同时复用了我们常用的查询以及增加、删除、编辑代码。至于为什么要使用接口,是为了满足面向对象原则的依赖倒转原则——抽象不依赖细节,细节应该依赖 抽象。

      BLL层代码结构与DAL类似。

      一个简单的多层架构就是这样,各层之间引用关系从顶层向下调用底层,将各层之间耦合尽量降低。


      然后,谈谈配置autofac。

      这里,发现这工具很好,很强大,至于有多强大,我也不清楚,因为我也很菜(/ □ )……

      autofac配置园里相关文章也很多,我这里就初略的说说。

      First step:nuget上加入我们autofac的程序集引用:

      

      注意,根据你所使用的.net环境选择相应的程序集,目前最新的版本是3.1.0,低版本的autofac是不支持.net4.0的。我们这里使用了MVC4.0所以选择第二个。

      Second step:配置依赖注入,说白了就是告诉autofac你要将哪个类与接口“发生关系”。

      

      在这个框架中,我们将配置信息在图示类中完成:

    namespace YTJWGL_WebUI.RegisterAutofac
    {
        public static class RegisterAutofacForSingle
        {
            public static void RegisterAutofac()
            {
                ContainerBuilder builder = new ContainerBuilder();
                builder.RegisterControllers(Assembly.GetExecutingAssembly());
    
                #region IOC注册区域
                //倘若需要默认注册所有的,请这样写(主要参数需要修改)
                //builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
                //   .AsImplementedInterfaces();
               
                //Admin
                builder.RegisterType<AdminService>().As<IAdminService>().InstancePerHttpRequest();
    
              
                #endregion
                // then
                var container = builder.Build();
                DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
              
            }
    
           
        }
    }
    RegisterAutofacForSingle

      autofac有很多重配置方式,详询此处:http://www.cnblogs.com/hkncd/archive/2012/11/28/2792474.html

      好了,下面我们在全局文件Global.asax中调用刚才定义的方法:

    1 namespace YTJWGL_WebUI
     2 {
     3     // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
     4     // visit http://go.microsoft.com/?LinkId=9394801
     5     public class MvcApplication : System.Web.HttpApplication
     6     {
     7         protected void Application_Start()
     8         {
     9             AreaRegistration.RegisterAllAreas();
    10 
    11             WebApiConfig.Register(GlobalConfiguration.Configuration);
    12             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    13             RouteConfig.RegisterRoutes(RouteTable.Routes);
    14 
    15             //autofac注册
    16             RegisterAutofacForSingle.RegisterAutofac();
             
    18 
    19             //automapper注册
    20             RegisterAutomapper.Excute();
    21         }
    22     }
    23 }
    Global.asax

      至此,autofac的配置就基本OK。其是用也比较的方便,autofac是使用构造函数注入:

    
    
     1 namespace YTJWGL_WebUI.Areas.Admin.Controllers
     2 {
     3     
     4     public class FrameController : Controller
     5     {
     6         //
     7         // GET: /Admin/Frame/
     8         #region Fields
     9 
    10         private readonly IAdminService _adminService;
    11        
    12         #endregion
    13 
    14         #region Constructors
    15 
    16         public FrameController(IAdminService adminService)
    17         {
    18             this._adminService = adminService;        
    19         }
    20         #endregion
    21 
    22         #region Admin
    23 
    24         [HttpPost]
    25         public ActionResult Login(LoginModel model, string returnUrl)
    26         {
    27          //这样调用
    28            var amin = _adminService.GetAllEntities(p => p.ID != 0);
    29         }
    36     }
    37 }
    FrameController

      这样就可以使用接口调用方法了。autofac简单配置完毕。


      接下来我们配置automapper:

      First Step:与autofac同样的方法在nuget里面安装。

      Secoud Step:

        

      我把automapper分为两部配置,第一步与autofac类似,首先注册,也就是告诉automapper组件,你要在哪两个Model之间映射:

     1 namespace YTJWGL_WebUI.Automapper
     2 {
     3     public static class RegisterAutomapper
     4     {
     5         public static void Excute()
     6         {
     7 
     8             //Admin
     9             Mapper.CreateMap<LoginModel, YTJWGL_Admin>();
    10             Mapper.CreateMap<YTJWGL_Admin, LoginModel>().ForMember(dest => dest.ValidatorCode, sor => sor.Ignore());
    11      
    12         }
    13 
    14     }
    15 }
    View Code
    RegisterAutomapper

      代码中Formeber后面的代码可以不要,详情在这:http://www.cnblogs.com/ljzforever/archive/2011/12/29/2305500.html;

      然后看看我们第二个文件MapperExtention:

     1 namespace YTJWGL_WebUI.Automapper
     2 {
     3     public static class MapperExtention
     4     {
     5         #region Admin
     6 
     7        public static AdminModel ToModel(this YTJWGL_Admin entity)
     8         {
     9             return Mapper.Map<YTJWGL_Admin, AdminModel>(entity);
    10         }
    11 
    12         public static YTJWGL_Admin ToEntity(this AdminModel model)
    13         {
    14             return Mapper.Map<AdminModel, YTJWGL_Admin>(model);
    15         }
    16 
    17         public static YTJWGL_Admin ToEntity(this AdminModel model, YTJWGL_Admin destination)
    18         {
    19             return Mapper.Map<AdminModel, YTJWGL_Admin>(model, destination);
    20         }
    21     
    22     }
    23 }
    MapperExtention中定义了一个个拓展方法,添加这个文件会让我们在控制器中映射实体变得非常方便:
     public ActionResult List()
    2         {
    3             //数据库实体向ViewModel转换
    4             var model = _newsService.GetEntityByQuery(p => p.ID == 1).ToModel();
    5             //ViewModel向数据库实体转换
    6             var entity = model.ToEntity();
    7             return View();
    8         }

      就向调用ToString()方法一样的使用。

      当然,我们的automapper还需要在Global文件中调用,这一步在autofac最后一张图中已经说明。

  • 相关阅读:
    javascript中构造函数与普通函数的区别还有关于“new”操作符的一些原理
    一个简单的jquery左右列表内容切换应用
    Spring学习笔记(三)之装配Bean
    Maven引入jar的总结
    在使用hibernate的getHibernateTemplate()时怎么让控制台输出封装好的SQL? 怎么用日志打印出来?
    Spring学习笔记(二)之装配Bean
    spring学习笔记(一) Spring概述
    ResourceBundle读取文件学习
    如何从结果集中遍历得到一条条的数据?
    response与request回顾学习
  • 原文地址:https://www.cnblogs.com/shengfa/p/4022948.html
Copyright © 2020-2023  润新知