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


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


一、目录

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

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

 3、Ligerui首页的快速搭建

二、正文

 多层架构中等以上规模以上的系统用得比较多,此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层文件:

1 namespace YTJWGL_IDao 2 { 3     public interface IAdminDao<T> : IBaseDao<T> where T : class
4  { 5 
6  } 7 }
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(); 17           
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  } 30 
31     
32 
33        
34        
35       
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 }
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

  MapperExtention中定义了一个个拓展方法,添加这个文件会让我们在控制器中映射实体变得非常方便:

  

1  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         }
List

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

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

  下一篇,准备写一个mvc中验证码实现。


2013-11-29 21:26:00

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM