啊,终于到写三层架构的时候了,老实说,我都不知道自己这个算不算三层架构,姑且就当它是吧,具体属于哪一个体系,希望有大佬指点一下(^o^)/
不晓得有人注意到没有,我写了三篇博客,然后就改了三次标题ヽ( ̄▽ ̄)?,
从最开始的Core建数据库,到Core数据库操作,再到现在的Core建站,也算是下决心写个系列啊,,感觉要更好久的样子,,
好吧,不要在意那些细节,文中可能会有一些我不知道的坑,毕竟自己也是一边自学一边写,不过保证功能还是能用的,发现有坑记得说,,我改,,(〃‘▽‘〃)
// ===================emmm,我是分割线===================
强烈推荐阅读:设计模式六大原则 讲的相当浅显易懂,,
首先上一个截图,看看现在的项目结构,今天的主角是DataBase文件里面的那一堆项目啊,BLL,DAL和Interface,,Models是生成数据库时使用的,所以今天用不上,,
按我的理解,先说说正常的三层架构吧,
UI:界面层,这个层最简单,只是给BLL传递数据,然后,将BLL返回的数据进行一些处理,方便展示,
BLL:业务逻辑层,接收UI层给的数据,写一些业务逻辑,第一步干啥,第二步干啥,什么什么的,然后把界面需要的数据返回出去,感觉更像是一个API
DAL:数据访问层,BLL的业务逻辑处理时,总要涉及到数据库的操作,这时候就要用到DAL层了,,
还有一个Model层,用来传递数据的,,不在三层范畴,,,
不知道大家是怎么使用三层的,给大家展示一下以前学校教我们怎么用的三层架构啊,,
分别对应三个类,UI层:HomeController,BLL层:DT_UserBLL,DAL层:DT_UserDAL
1 // UI层 2 public IActionResult Index(int userID) 3 { 4 5 // 根据条件,返回用户 6 // 和BLL说,给你一堆条件,帮我把这些人找出来 7 var userList = DT_UserBLL.GetUser(0,18); 8 9 return View(userList); 10 11 }
1 /// <summary> 2 /// BLL层,返回符合条件的用户 3 /// </summary> 4 /// <param name="sex">性别</param> 5 /// <param name="age">年龄</param> 6 /// <returns></returns> 7 public List<DT_User> GetUser(int sex, int age) 8 { 9 10 #region 数据校验 11 12 // 性别检测,0:女,1:男 13 if (sex != 0 && sex != 1) 14 // 拒绝人妖 15 return null; 16 17 // 年龄检测,[0,150]岁 18 if (age < 0 || 150 < age) 19 // 拒绝妖怪 20 return null; 21 22 #endregion 23 24 // 和DAL说,数据我校验好了,不是恶搞, 25 // 帮我查出来这些人,然后我交给UI就完事儿了,, 26 return DT_UserDAL.GetUser(int sex, int age).ToList(); 27 }
1 /// <summary> 2 /// DAL层,返回符合条件的用户 3 /// </summary> 4 /// <param name="sex">性别</param> 5 /// <param name="age">年龄</param> 6 /// <returns></returns> 7 public IQueryable<DT_User> GetUser(int sex, int age) 8 { 9 DbContext DB = new DbContext(); 10 11 return DB.Set<DT_User>().Where(c=>c.Sex==sex&&c.Age==age); 12 }
当时学着感觉蛮好的,挺新奇的一个编程思想,不过每一个数据表对应的DAL里面都得写一套增删查改,,简直是灾难,,[○?`Д´? ○]
出来实习之后,花了个把星期,把我们老大写的一个框架看明白了,就按图索骥地写了起来,嘿嘿
其实和三层架构差不多的,只是把每个数据表对应的DAL里面的增删查改全部提出来,封装成了一个类,,
然后对这个类进行继承,具体操作如下,,,
首先啊,要大概了解一下依赖注入,,讲真,这个我也是一脸懵逼,所以就不复制百度百科了,,
说说自己的理解吧,,,,emmm,此处可能有大量谬论,建议不要被我误导了,看看就好,别往心里去
依赖注入这东西就好像一个全局的字典类型变量,,都是以键值对的方式存储的
因为注册依赖注入服务的大部分语法是酱紫的,,,
1 services.AddTransient(typeof(IDT_UserService), typeof(DT_UserService));
而services这个变量的话,就像一个容器,用来存储这些键值对的,具体从哪来的,我也不知道,ヽ( ̄д ̄;)ノ
而要使用的话,语法是酱紫的,,,
1 public class HomeController : Controller 2 { 3 private IDT_UserService _UserService; 4 5 public HomeController(IDT_UserService _UserService) 6 { 7 // 依赖注入得到实例 8 this._UserService = _UserService; 9 } 10 11 public IActionResult Index() 12 { 13 ViewBag.list = _UserService.LoadEntites(c => true); 14 15 return View(); 16 } 17 }
对的,完全不需要new,,其原理,,起码我不晓得,感觉甚是神奇,,
先注册一个依赖注入的服务,然后要实例的时候,直接在构造函数里面把键的类型写上就好,,
好了,灌毒就到此为止了,,还是继续上代码吧,,
首先,得写一个数据库操作的底层类DalService又因为很多地方调用,所以,肯定是泛型,,
然后为了解耦和方便注入,所以实现一个接口IDalService,
我暂时只写了添加和查询的方法,,其他的方法可以自由发挥,,不过记得先写接口,然后去实现接口中新加的方法,,不然无法使用的,,
1 public interface IDalService<T> where T : class, new() 2 { 3 T AddEntity(T entity); 4 5 IQueryable<T> LoadEntites(Expression<Func<T, bool>> where); 6 7 int SaveChanges(); 8 9 }
IDalService
1 /// <summary> 2 /// 数据访问层:DAL 3 /// </summary> 4 /// <typeparam name="T"></typeparam> 5 public class DalService<T> : IDalService<T> where T : class, new() 6 { 7 8 private DbContext DbWrite; 9 10 /// <summary> 11 /// 获得数据库上下文 12 /// </summary> 13 /// <param name="dbContext">数据库上下文类,各自更改成自己的</param> 14 public DalService(DBCodeFirst dbContext) 15 { 16 DbWrite = dbContext; 17 } 18 19 public T AddEntity(T entity) 20 { 21 DbWrite.Set<T>().Add(entity); 22 return entity; 23 } 24 25 public IQueryable<T> LoadEntites(Expression<Func<T, bool>> where) 26 { 27 return DbWrite.Set<T>().Where(where); 28 } 29 30 public int SaveChanges() 31 { 32 return DbWrite.SaveChanges(); 33 } 34 35 }
DalService
然后就没有DAL层啥事了,,咱们去看BLL层
同样的写一个业务逻辑的父级类BllService,依旧是泛型,以及实现接口IBllService
1 public interface IBllService<T>where T : class, new() 2 { 3 T AddEntity(T entity,bool IsSave); 4 5 IQueryable<T> LoadEntites(Expression<Func<T, bool>> where); 6 7 int SaveChanges(); 8 }
IBllService
1 /// <summary> 2 /// 数据逻辑层:BLL 3 /// </summary> 4 public class BllService<T> : IBllService<T> where T : class, new() 5 { 6 7 /// <summary> 8 /// 数据库服务 9 /// </summary> 10 protected IDalService<T> DBService; 11 12 public BllService(IDalService<T> dalService) 13 { 14 this.DBService = dalService; 15 } 16 17 /// <summary> 18 /// 保存实体 19 /// </summary> 20 /// <param name="entity"></param> 21 /// <param name="IsSave"></param> 22 /// <returns></returns> 23 public T AddEntity(T entity, bool IsSave) 24 { 25 entity = DBService.AddEntity(entity); 26 if (IsSave) 27 { 28 if (SaveChanges() > 0) 29 return null; 30 } 31 return entity; 32 } 33 34 /// <summary> 35 /// 查询数据 36 /// </summary> 37 /// <param name="where"></param> 38 /// <returns></returns> 39 public IQueryable<T> LoadEntites(Expression<Func<T, bool>> where) 40 { 41 return DBService.LoadEntites(where); 42 } 43 44 /// <summary> 45 /// 保存数据库 46 /// </summary> 47 /// <returns></returns> 48 public int SaveChanges() 49 { 50 return DBService.SaveChanges(); 51 } 52 }
BllService
然后基本就完成了,,我们可以在BLL层创建一个DT_User的逻辑处理类,继承BllService,并实现接口IDT_UserService
1 public interface IDT_UserService : IBllService<DT_User> 2 { 3 DT_User Insert(); 4 5 List<DT_User> GetList(); 6 }
IDT_UserService
1 public class DT_UserService : BllService<DT_User>, IDT_UserService 2 { 3 /// <summary> 4 /// 用于实例化父级,DBService变量 5 /// </summary> 6 /// <param name="dal"></param> 7 public DT_UserService(IDalService<DT_User> dal) : base(dal) 8 { 9 10 } 11 12 public DT_User Insert() 13 { 14 DT_User user = new DT_User 15 { 16 Password = new Random().Next(0, 101) + "", 17 UserName = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") 18 }; 19 return AddEntity(user, true); 20 } 21 22 public List<DT_User> GetList() 23 { 24 return LoadEntites(c => true).ToList(); 25 } 26 27 }
DT_UserService
最后使用的话,要把他们统统注册到服务里面,新建一个类DIBllRegister,用来注册这些和数据库相关的服务
1 /// <summary> 2 /// Bll层依赖注入 3 /// </summary> 4 public class DIBllRegister 5 { 6 7 public void DIRegister(IServiceCollection services) 8 { 9 // 用于实例化DalService对象,获取上下文对象 10 services.AddTransient(typeof(IDalService<>), typeof(DalService<>)); 11 12 // 配置一个依赖注入映射关系 13 services.AddTransient(typeof(IDT_UserService), typeof(DT_UserService)); 14 } 15 }
DIBllRegister
在Startup的ConfigureServices方法中添加两行代码
1 /// <summary> 2 /// 运行时调用此方法。使用此方法向容器添加服务。 3 /// </summary> 4 /// <param name="services"></param> 5 public void ConfigureServices(IServiceCollection services) 6 { 7 services.AddOptions(); 8 9 // 数据库连接字符串 10 var conStr = Config.GetVal<string>(ConfigKey.ConStr); 11 services.AddDbContext<DBCodeFirst>(options => options.UseSqlServer(conStr)); 12 13 DIBllRegister bllRegister = new DIBllRegister(); 14 bllRegister.DIRegister(services); 15 16 services.AddMvc(); 17 }
然后我们就可以愉快的使用三层架构来写项目了,,ヽ(≧∀≦)?
示例以及项目结构如下:
运行结果:
注意事项:
- BLL层的类一定要继承BllService,并实现它对应的接口,参考上文DT_UserService类的格式
- BLL,DAL任何类要添加方法时,一定要在对应的接口中有个同样的入口,不然无法调用
- BLL层添加类时,记得在DIBllRegister的DIRegister中添加一行注册服务的代码,不然无法调用
- 差不多就这些,我想起来了再加,,,
其实这个是我从Framework搬过来的,心塞得简直不要不要的,,,填坑日记就不写出来了,,
具体的搭建思想也不太好用文字表述,大佬不要吐槽,萌新可以照着步骤去建一个小项目调试着看,,
个人感觉还是比较好懂的,,毕竟,基本上全是核心代码还带注释,加一个使用样例,
然后就是下集预告了,云服务器的FTP发布和数据库连接吧,,毕竟云服务器到手辣么久了,也该拉出来溜溜,,(?´?`?)*??*
最后,,有坑记得说,,,,
原文地址:https://www.cnblogs.com/Onlooker/p/8231522.html