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

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


一、目录

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

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

二、正文

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

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

多层架构+MVC+EF+AUTOFAC+AUTOMAPPER_第1张图片

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

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

class="code_img_closed" src="/Upload/Images/2013113016/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('04dfa4e5-5ea4-401d-8696-ca7511b37b40',event)" src="/Upload/Images/2013113016/2B1B950FA3DF188F.gif" alt="" />

 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的程序集引用:

  多层架构+MVC+EF+AUTOFAC+AUTOMAPPER_第2张图片

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

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

  多层架构+MVC+EF+AUTOFAC+AUTOMAPPER_第3张图片

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

  

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:

    多层架构+MVC+EF+AUTOFAC+AUTOMAPPER_第4张图片

  我把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最后一张图中已经说明。

你可能感兴趣的:(mapper)