原本关于T4模板原想分5个章节详细解说的,不过因为最近比较忙,也不想将整个系列时间拉得太长,所以就将它们整合在一块了,可能会有很多细节没有讲到,希望大家自己对着代码与模板去研究。
本章代码量会比较大,基本将Web层要使用到的大部分函数都用模板生成了出来,而模板中的函数,很多也是互相关联调用的。另外在DotNet.Utilities(公共函数项目)中也添加与修改了一些类和函数。
需要特别说明的是,在逻辑层添加了July大神编写的超强上传类,具体怎么使用功能怎么强大,在后面调用到时会用一个章节详细说明。呵呵......
1、先了解解决方案中各个新增文件功能,具体的文件对应说明,请查看《数据字典》中的“目录与文件说明”
这个是各个表对应的逻辑层类,里面是Web层常用的各种函数。Application文件夹是各种公共逻辑层函数类,Systems文件夹是后端系统管理模块常用函数类。以后添加新的文件时,可以按功能或业务进行对应分类存放。
LogicBase.cs是逻辑层所有模板生成类的父类,里面有两个虚函数,用来给模板类调用。在有需要的时候,在自定义类中重写这两个函数,就可以给模板中的相应函数自动调用执行。
DelCache()函数是模板类中进行添加、修改、删除、更新等对数据库记录进行变更时会同步调用到,主要用于拥有自定义缓存的类中,重写该函数后,进行前面的各项操作时自动执行该函数,以达到同步理清自定义缓存的功能。
GetExpression()函数是提供给模板类中的缓存加载函数(GetList())使用的。我们在开发时会创建很多表,有些表全部记录需要加载到缓存中;有一些表记录不需要加载到缓存当中(比如日志表);同时也有一些表的记录会过期,只需要加载指定条件的记录到缓存使用就可以了,对于后者我们就可以使用GetExpression()函数来进行控制,只要重写这个函数,系统在运行GetList()函数时就会自动加载我们自定义的条件,从数据库中筛选出我们想要的记录到缓存中。
CommonBll.cs是逻辑层的工具类,主要提供给模板生成类调用。具体使用方法请看注释和相关例子。
2、逻辑层T4模板文件CreateBll.tt(文件在文章后面下载源码里)
模板运行后将会生成下图中的这些函数
其中IIS缓存又包含下图中这些常用函数
原来是想使用Redis来处理缓存的,后来考虑到对于中小型项目来说,很多都没有独立的空间,使用的是虚拟机,用Redis也就不是很合适了,所以换成IIS缓存来处理
IIS缓存也由之前的表级别缓存修改为记录级别了,就是说你对某一条记录进行添加、删除、修改、更新等操作时,不用清空整个表缓存,直接对缓存中的记录进行操作,不过这个功能刚刚改为记录级别,得Web层代码开始写后才能测试看看效果怎么样
3、主要模板函数功能说明
1)模板函数调用使用单例模式
对于中小型项目来说,访问量并发量并不是很大,单例模式已经够用了,如果对某一个表并发量过大时,怕出现问题,也可以直接new出这个类,不使用单例调用就可以了
比如:
单例模式调用
InformationBll.GetInstence().GetList();
非单例模式调用
var information = new InformationBll(); information.GetList();
2)表缓存函数
1 private const string const_CacheKey = "Cache_Information"; 2 private const string const_CacheKey_Date = "Cache_Information_Date"; 3 4 #region 清空缓存 5 /// <summary>清空缓存</summary> 6 private void DelAllCache() 7 { 8 //清除模板缓存 9 CacheHelper.RemoveOneCache(const_CacheKey); 10 CacheHelper.RemoveOneCache(const_CacheKey_Date); 11 12 //清除前台缓存 13 CommonBll.RemoveCache(const_CacheKey); 14 //运行自定义缓存清理程序 15 DelCache(); 16 } 17 #endregion 18 19 #region IIS缓存函数 20 21 #region 从IIS缓存中获取Information表记录 22 /// <summary> 23 /// 从IIS缓存中获取Information表记录 24 /// </summary> 25 /// <param name="isCache">是否从缓存中读取</param> 26 public IList<DataAccess.Model.Information> GetList(bool isCache = true) 27 { 28 try 29 { 30 //判断是否使用缓存 31 if (CommonBll.IsUseCache() && isCache){ 32 //检查指定缓存是否过期——缓存当天有效,第二天自动清空 33 if (CommonBll.CheckCacheIsExpired(const_CacheKey_Date)){ 34 //删除缓存 35 DelAllCache(); 36 } 37 38 //从缓存中获取DataTable 39 var obj = CacheHelper.GetCache(const_CacheKey); 40 //如果缓存为null,则查询数据库 41 if (obj == null) 42 { 43 var list = GetList(false); 44 45 //将查询出来的数据存储到缓存中 46 CacheHelper.SetCache(const_CacheKey, list); 47 //存储当前时间 48 CacheHelper.SetCache(const_CacheKey_Date, DateTime.Now); 49 50 return list; 51 } 52 //缓存中存在数据,则直接返回 53 else 54 { 55 return (IList<DataAccess.Model.Information>)obj; 56 } 57 } 58 else 59 { 60 //定义临时实体集 61 IList<DataAccess.Model.Information> list = null; 62 63 //获取全表缓存加载条件表达式 64 var exp = GetExpression<Information>(); 65 //如果条件为空,则查询全表所有记录 66 if (exp == null) 67 { 68 //从数据库中获取所有记录 69 var all = Information.All(); 70 list = all == null ? null : Transform(all.ToList()); 71 } 72 else 73 { 74 //从数据库中查询出指定条件的记录,并转换为指定实体集 75 var all = Information.Find(exp); 76 list = all == null ? null : Transform(all); 77 } 78 79 return list; 80 } 81 } 82 catch (Exception e) 83 { 84 //记录日志 85 CommonBll.WriteLog("从IIS缓存中获取Information表记录时出现异常", e); 86 } 87 88 return null; 89 } 90 #endregion
只要调用了GetList()函数,系统就会将全表记录(重写GetExpression()函数的,只加载符合条件的记录)以IList<T>存储方式缓存到IIS缓存中,供其他相关函数使用,缓存当天有效,第二天访问时会自动清空重新加载
一般来说,前端与后端在一个项目时,后端操作缓存会直接影响前端的数据。如果前后端分开,做为两个项目来开发时,进行增、删、改操作时就必须调用DelAllCache()函数来清除前后端的缓存,以便两个站点的缓存能及时同步(目前对于使用IIS缓存跨站点记录级别缓存同步还没有一个比较好的处理方法,只能直接清空整表缓存来实现),调用DelAllCache()函数时,会执行CommonBll.RemoveCache(const_CacheKey)函数,该函数会通过一个前端访问接口,发送经过加密处理后的数据,前端接口接收到请求后再清除对应缓存来实现前后端IIS缓存同步功能。
3)实体转换函数
1 #region 实体转换
2 /// <summary> 3 /// 将Information记录实体(SubSonic实体)转换为普通的实体(DataAccess.Model.Information) 4 /// </summary> 5 /// <param name="model">SubSonic插件生成的实体</param> 6 /// <returns>DataAccess.Model.Information</returns> 7 public DataAccess.Model.Information Transform(Information model) 8 { 9 if (model == null) 10 return null; 11 12 return new DataAccess.Model.Information 13 { 14 Id = model.Id, 15 InformationClass_Root_Id = model.InformationClass_Root_Id, 16 InformationClass_Root_Name = model.InformationClass_Root_Name, 17 InformationClass_Id = model.InformationClass_Id, 18 InformationClass_Name = model.InformationClass_Name, 19 Title = model.Title, 20 RedirectUrl = model.RedirectUrl, 21 Content = model.Content, 22 Upload = model.Upload, 23 FrontCoverImg = model.FrontCoverImg, 24 Note = model.Note, 25 NewsTime = model.NewsTime, 26 Keywords = model.Keywords, 27 SeoTitle = model.SeoTitle, 28 SeoKey = model.SeoKey, 29 SeoDesc = model.SeoDesc, 30 Author = model.Author, 31 FromName = model.FromName, 32 Sort = model.Sort, 33 IsDisplay = model.IsDisplay, 34 IsHot = model.IsHot, 35 IsTop = model.IsTop, 36 IsPage = model.IsPage, 37 IsDel = model.IsDel, 38 CommentCount = model.CommentCount, 39 ViewCount = model.ViewCount, 40 AddYear = model.AddYear, 41 AddMonth = model.AddMonth, 42 AddDay = model.AddDay, 43 AddDate = model.AddDate, 44 Manager_Id = model.Manager_Id, 45 Manager_CName = model.Manager_CName, 46 UpdateDate = model.UpdateDate, 47 }; 48 } 49 50 /// <summary> 51 /// 将Information记录实体集(SubSonic实体)转换为普通的实体集(DataAccess.Model.Information) 52 /// </summary> 53 /// <param name="sourceList">SubSonic插件生成的实体集</param> 54 public IList<DataAccess.Model.Information> Transform(IList<Information> sourceList) 55 { 56 //创建List容器 57 var list = new List<DataAccess.Model.Information>(); 58 //将SubSonic插件生成的实体集转换后存储到刚创建的List容器中 59 sourceList.ToList().ForEach(r => list.Add(Transform(r))); 60 return list; 61 } 62 63 /// <summary> 64 /// 将Information记录实体由普通的实体(DataAccess.Model.Information)转换为SubSonic插件生成的实体 65 /// </summary> 66 /// <param name="model">普通的实体(DataAccess.Model.Information)</param> 67 /// <returns>Information</returns> 68 public Information Transform(DataAccess.Model.Information model) 69 { 70 if (model == null) 71 return null; 72 73 return new Information 74 { 75 Id = model.Id, 76 InformationClass_Root_Id = model.InformationClass_Root_Id, 77 InformationClass_Root_Name = model.InformationClass_Root_Name, 78 InformationClass_Id = model.InformationClass_Id, 79 InformationClass_Name = model.InformationClass_Name, 80 Title = model.Title, 81 RedirectUrl = model.RedirectUrl, 82 Content = model.Content, 83 Upload = model.Upload, 84 FrontCoverImg = model.FrontCoverImg, 85 Note = model.Note, 86 NewsTime = model.NewsTime, 87 Keywords = model.Keywords, 88 SeoTitle = model.SeoTitle, 89 SeoKey = model.SeoKey, 90 SeoDesc = model.SeoDesc, 91 Author = model.Author, 92 FromName = model.FromName, 93 Sort = model.Sort, 94 IsDisplay = model.IsDisplay, 95 IsHot = model.IsHot, 96 IsTop = model.IsTop, 97 IsPage = model.IsPage, 98 IsDel = model.IsDel, 99 CommentCount = model.CommentCount, 100 ViewCount = model.ViewCount, 101 AddYear = model.AddYear,