http://www.cnblogs.com/Jnw-qianxi/p/3450344.html



多层架构+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 }
复制代码

  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 }
复制代码

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

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

复制代码
1 namespace YTJWGL_IDao
2 {
3     public interface IAdminDao<T> : IBaseDao<T> where T : class
4     {
5 
6     }
7 }
复制代码
1 namespace YTJWGL_EFDao
2 {
3     public class AdminEFDao : BaseEFDao<YTJWGL_Admin>, IAdminDao<YTJWGL_Admin>
4     {
5     }
6 }

   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));
          
        }

       
    }
}
复制代码

  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 }
复制代码

  至此,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 }
复制代码

  这样就可以使用接口调用方法了。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 }
复制代码

  代码中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中定义了一个个拓展方法,添加这个文件会让我们在控制器中映射实体变得非常方便:

  

复制代码
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         }
复制代码

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

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

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


2013-11-29 21:26:00

 



本文转载:CSDN博客