这应该是本系统最后一次重构,将重构BLL层和Model层。来彻底取代代码生成器生成的BLL层和DAL层。彻底废掉了代码生成器的DAL,BLL,MODEL层。html
全自动生成增,删,改,查的通用方法和模型转换与BLL层的模型事务脱离,后续文章,会以一些插件或功能为目的,继续完善,进行分享,最后60节的文章会对本系统作一个总结前端
(可是还没时间写,相信60节的文章能让你快速了解到本系统的优点和架构,就算你从未阅读以前的全部文章)架构
继上次的DAL层重构(上一节),原本只想重构DAL层算了,可是鉴于本人是代码强迫症患者,因此花了些时间把BLL层重构。app
在此务必共鸣一个问题,代码重构不是架构改变,这个系统的架构彻底仍是原来的接口多层注入架构!以下图所示彻底不变ide
最后必须让初学者理解一个知识点:分部类 partial 关键字,由于咱们的重构是围绕分部类而实现,包括接口ui
partial 关键字指示可在命名空间中定义该类、结构或接口的其余部分。全部部分都必须使用 partial 关键字。在编译时,各个部分都必须可用来造成最终的类型。各个部分必须具备相同的可访问性,如 public、private 等。this
若是将任意部分声明为抽象的,则整个类型都被视为抽象的。若是将任意部分声明为密封的,则整个类型都被视为密封的。若是任意部分声明基类型,则整个类型都将继承该类。spa
指定基类的全部部分必须一致,但忽略基类的部分仍继承该基类型。各个部分能够指定不一样的基接口,最终类型将实现全部分部声明所列出的所有接口。在某一分部定义中声明的任何类、结构或接口成员可供全部其余部分使用。最终类型是全部部分在编译时的组合。插件
下列声明:debug
partial class Earth : Planet, IRotate { } partial class Earth : IRevolve { }
等效于下列声明:
class Earth : Planet, IRotate, IRevolve { }
相比咱们DAL层,重构BLL层是有技术难度的,由于业务层涉及模型的转换构成,虽然只重构模块的(增、删、改、查),下面咱们开始
下载上一节代码(https://yunpan.cn/cYUdjssbmiLrL 访问密码 e622)来分析业务层。
分析:IBLL,BLL
IBLL层不用说了,跟IDAL层是一致的
因此咱们直接复制IDAL的TT模版修改后以下
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ include file="../../Apps.Models/Common.ttinclude"#><#@ output extension=".cs"#> <# const string inputFile = @"../../Apps.Models/DB.edmx"; var textTransform = DynamicTextTransformation.Create(this); var code = new CodeGenerationTools(this); var ef = new MetadataTools(this); var typeMapper = new TypeMapper(code, ef, textTransform.Errors); var fileManager = EntityFrameworkTemplateFileManager.Create(this); var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) { return string.Empty; } WriteHeader(codeStringGenerator, fileManager); foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { fileManager.StartNewFile("I"+entity.Name + "BLL.cs"); #> using System; using Apps.Common; using System.Collections.Generic; using Apps.Models<#=entity.Name.IndexOf("_")>0?"."+entity.Name.Substring(0,entity.Name.IndexOf("_")):".Sys" #>; namespace Apps.IBLL { public partial interface I<#=entity.Name #>BLL { List<<#=entity.Name #>Model> GetList(ref GridPager pager, string queryStr); bool Create(ref ValidationErrors errors, <#=entity.Name #>Model model); bool Delete(ref ValidationErrors errors, string id); bool Delete(ref ValidationErrors errors, string[] deleteCollection); bool Edit(ref ValidationErrors errors, <#=entity.Name #>Model model); <#=entity.Name #>Model GetById(string id); bool IsExists(string id); } <# EndNamespace(code); } fileManager.Process(); #>
很是好。业务层完成跟预期是同样的!这样咱们直接能够看到咱们原来的ISysSample能够由
using System.Collections.Generic; using Apps.Common; using Apps.Models.Sys; namespace Apps.IBLL { public interface ISysSampleBLL { List<SysSampleModel> GetList(ref GridPager pager, string queryStr); bool Create(ref ValidationErrors errors, SysSampleModel model); bool Delete(ref ValidationErrors errors, string id); bool Delete(ref ValidationErrors errors, string[] deleteCollection); bool Edit(ref ValidationErrors errors, SysSampleModel model); SysSampleModel GetById(string id); bool IsExist(string id); } }
变为--->
using System.Collections.Generic; using Apps.Common; using Apps.Models.Sys; namespace Apps.IBLL { public partial interface ISysSampleBLL { } }
代码行数发生质的改变,能够咱们就能够扩展本身的接口方法,利用partial类
照样画葫芦,业务层也生成
直接上TT代码
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ include file="../../Apps.Models/Common.ttinclude"#><#@ output extension=".cs"#> <# const string usingName = ""; const string inputFile = @"../../Apps.Models/DB.edmx"; var textTransform = DynamicTextTransformation.Create(this); var code = new CodeGenerationTools(this); var ef = new MetadataTools(this); var typeMapper = new TypeMapper(code, ef, textTransform.Errors); var fileManager = EntityFrameworkTemplateFileManager.Create(this); var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) { return string.Empty; } WriteHeader(codeStringGenerator, fileManager); foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { if(entity.Name.StartsWith("Sys") || entity.Name.StartsWith("JOB")) { fileManager.StartNewFile(""+entity.Name + "BLL.cs"); var simpleProperties = typeMapper.GetSimpleProperties(entity); #> using System; using System.Collections.Generic; using System.Linq; using Apps.Models; using Apps.Common; using Microsoft.Practices.Unity; using System.Transactions; using Apps.IBLL; using Apps.IDAL; using Apps.BLL.Core; using Apps.Locale; using Apps.Models<#=entity.Name.IndexOf("_")>0?"."+entity.Name.Substring(0,entity.Name.IndexOf("_")):".Sys" #>; namespace Apps.BLL { public partial class <#=entity.Name #>BLL:I<#=entity.Name #>BLL { [Dependency] public I<#=entity.Name #>Repository m_Rep { get; set; } public virtual List<<#=entity.Name #>Model> GetList(ref GridPager pager, string queryStr) { IQueryable<<#=entity.Name #>> queryData = null; if (!string.IsNullOrWhiteSpace(queryStr)) { queryData = m_Rep.GetList( <# int i =0; if (simpleProperties.Any()){foreach(var edmProperty in simpleProperties){ if(i==0) { #> <#=codeStringGenerator.Property(edmProperty).ToString().IndexOf("string")>0?"a=>a."+edmProperty+".Contains(queryStr)":""#> <# if(codeStringGenerator.Property(edmProperty).ToString().IndexOf("string")>0) { i=1; } } else if(i==1) {#> <#=codeStringGenerator.Property(edmProperty).ToString().IndexOf("string")>0?"|| a."+edmProperty+".Contains(queryStr)":""#> <# } #> <#} }#> ); } else { queryData = m_Rep.GetList(); } pager.totalRows = queryData.Count(); //排序 queryData = LinqHelper.SortingAndPaging(queryData, pager.sort, pager.order, pager.page, pager.rows); return CreateModelList(ref queryData); } public virtual List<<#=entity.Name #>Model> CreateModelList(ref IQueryable<<#=entity.Name #>> queryData) { List<<#=entity.Name #>Model> modelList = (from r in queryData select new <#=entity.Name #>Model { <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> <#=edmProperty#> = r.<#=edmProperty#>, <# } } #> }).ToList(); return modelList; } public virtual bool Create(ref ValidationErrors errors, <#=entity.Name #>Model model) { try { <#=entity.Name #> entity = m_Rep.GetById(model.Id); if (entity != null) { errors.Add(Resource.PrimaryRepeat); return false; } entity = new <#=entity.Name #>(); <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> entity.<#=edmProperty#> = model.<#=edmProperty#>; <# } } #> if (m_Rep.Create(entity)) { return true; } else { errors.Add(Resource.InsertFail); return false; } } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual bool Delete(ref ValidationErrors errors, string id) { try { if (m_Rep.Delete(id) == 1) { return true; } else { return false; } } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual bool Delete(ref ValidationErrors errors, string[] deleteCollection) { try { if (deleteCollection != null) { using (TransactionScope transactionScope = new TransactionScope()) { if (m_Rep.Delete(deleteCollection) == deleteCollection.Length) { transactionScope.Complete(); return true; } else { Transaction.Current.Rollback(); return false; } } } return false; } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual bool Edit(ref ValidationErrors errors, <#=entity.Name #>Model model) { try { <#=entity.Name #> entity = m_Rep.GetById(model.Id); if (entity == null) { errors.Add(Resource.Disable); return false; } <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> entity.<#=edmProperty#> = model.<#=edmProperty#>; <# } } #> if (m_Rep.Edit(entity)) { return true; } else { errors.Add("没有数据改变"); return false; } } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual <#=entity.Name #>Model GetById(string id) { if (IsExists(id)) { <#=entity.Name #> entity = m_Rep.GetById(id); <#=entity.Name #>Model model = new <#=entity.Name #>Model(); <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> model.<#=edmProperty#> = entity.<#=edmProperty#>; <# } } #> return model; } else { return null; } } public virtual bool IsExists(string id) { return m_Rep.IsExist(id); } public void Dispose() { } } <# EndNamespace(code); } } fileManager.Process(); #>
因为每个业务模型的属性都不一致,这里不能用List<T>来作,因此,一个表会生成一个BLL类。(图中红色部分)
若是生成红色部分。主要看下面代码
<# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> <#=edmProperty#> = r.<#=edmProperty#>, <# } } #>
获取表模型的全部属性,全部这段对不少人是有帮助的,请收藏,说不定你之后要用到
OK,编译经过,运行正确,仍是熟悉的面孔
可是至此。咱们的业务层和数据访问层,能够说是一行代码都没写。足够体现了TT模版的强大之处,相比咱们以前要用代码生成器来得极其方便
直到上面步骤,一切都很顺利,没有一点不妥。
有经验的园友会发现,里面东西都是写死的。并且分部类不能够重写本身。
好比说。我在处理 entity.Name = model.Name;时候我想entity.Name = model.Name.TrimStart() 去掉字符串前面的空格,那么能够看到根本没法操做。
然而咱们须要重写,可是又发现没法重写分部类的方法,怎么作?必须用一张图来看,我是这么作的
虚方法是能够重写的关键字是virtual 如下重写以后优先级高于前者 用override。用代码来讲明
改变一下CommonBLL.tt
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ include file="../../Apps.Models/Common.ttinclude"#><#@ output extension=".cs"#> <# const string usingName = ""; const string inputFile = @"../../Apps.Models/DB.edmx"; var textTransform = DynamicTextTransformation.Create(this); var code = new CodeGenerationTools(this); var ef = new MetadataTools(this); var typeMapper = new TypeMapper(code, ef, textTransform.Errors); var fileManager = EntityFrameworkTemplateFileManager.Create(this); var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) { return string.Empty; } WriteHeader(codeStringGenerator, fileManager); foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { if(entity.Name.StartsWith("Sys") || entity.Name.StartsWith("JOB")) { fileManager.StartNewFile("Virtual_"+entity.Name + "BLL.cs"); var simpleProperties = typeMapper.GetSimpleProperties(entity); #> using System; using System.Collections.Generic; using System.Linq; using Apps.Models; using Apps.Common; using Microsoft.Practices.Unity; using System.Transactions; using Apps.IBLL; using Apps.IDAL; using Apps.BLL.Core; using Apps.Locale; using Apps.Models<#=entity.Name.IndexOf("_")>0?"."+entity.Name.Substring(0,entity.Name.IndexOf("_")):".Sys" #>; namespace Apps.BLL { public class Virtual_<#=entity.Name #>BLL { [Dependency] public I<#=entity.Name #>Repository m_Rep { get; set; } public virtual List<<#=entity.Name #>Model> GetList(ref GridPager pager, string queryStr) { IQueryable<<#=entity.Name #>> queryData = null; if (!string.IsNullOrWhiteSpace(queryStr)) { queryData = m_Rep.GetList( <# int i =0; if (simpleProperties.Any()){foreach(var edmProperty in simpleProperties){ if(i==0) { #> <#=codeStringGenerator.Property(edmProperty).ToString().IndexOf("string")>0?"a=>a."+edmProperty+".Contains(queryStr)":""#> <# if(codeStringGenerator.Property(edmProperty).ToString().IndexOf("string")>0) { i=1; } } else if(i==1) {#> <#=codeStringGenerator.Property(edmProperty).ToString().IndexOf("string")>0?"|| a."+edmProperty+".Contains(queryStr)":""#> <# } #> <#} }#> ); } else { queryData = m_Rep.GetList(); } pager.totalRows = queryData.Count(); //排序 queryData = LinqHelper.SortingAndPaging(queryData, pager.sort, pager.order, pager.page, pager.rows); return CreateModelList(ref queryData); } public virtual List<<#=entity.Name #>Model> CreateModelList(ref IQueryable<<#=entity.Name #>> queryData) { List<<#=entity.Name #>Model> modelList = (from r in queryData select new <#=entity.Name #>Model { <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> <#=edmProperty#> = r.<#=edmProperty#>, <# } } #> }).ToList(); return modelList; } public virtual bool Create(ref ValidationErrors errors, <#=entity.Name #>Model model) { try { <#=entity.Name #> entity = m_Rep.GetById(model.Id); if (entity != null) { errors.Add(Resource.PrimaryRepeat); return false; } entity = new <#=entity.Name #>(); <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> entity.<#=edmProperty#> = model.<#=edmProperty#>; <# } } #> if (m_Rep.Create(entity)) { return true; } else { errors.Add(Resource.InsertFail); return false; } } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual bool Delete(ref ValidationErrors errors, string id) { try { if (m_Rep.Delete(id) == 1) { return true; } else { return false; } } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual bool Delete(ref ValidationErrors errors, string[] deleteCollection) { try { if (deleteCollection != null) { using (TransactionScope transactionScope = new TransactionScope()) { if (m_Rep.Delete(deleteCollection) == deleteCollection.Length) { transactionScope.Complete(); return true; } else { Transaction.Current.Rollback(); return false; } } } return false; } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual bool Edit(ref ValidationErrors errors, <#=entity.Name #>Model model) { try { <#=entity.Name #> entity = m_Rep.GetById(model.Id); if (entity == null) { errors.Add(Resource.Disable); return false; } <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> entity.<#=edmProperty#> = model.<#=edmProperty#>; <# } } #> if (m_Rep.Edit(entity)) { return true; } else { errors.Add(Resource.NoDataChange); return false; } } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } public virtual <#=entity.Name #>Model GetById(string id) { if (IsExists(id)) { <#=entity.Name #> entity = m_Rep.GetById(id); <#=entity.Name #>Model model = new <#=entity.Name #>Model(); <# if (simpleProperties.Any()) { foreach(var edmProperty in simpleProperties) { #> model.<#=edmProperty#> = entity.<#=edmProperty#>; <# } } #> return model; } else { return null; } } public virtual bool IsExists(string id) { return m_Rep.IsExist(id); } public void Dispose() { } } <# EndNamespace(code); } } fileManager.Process(); #>
更Common代码基本一致,只是头部变了,文件名称变了
public class Virtual_SysSampleBLL
那么从新建立一个CommonBLL.tt
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ include file="../../Apps.Models/Common.ttinclude"#><#@ output extension=".cs"#> <# const string usingName = ""; const string inputFile = @"../../Apps.Models/DB.edmx"; var textTransform = DynamicTextTransformation.Create(this); var code = new CodeGenerationTools(this); var ef = new MetadataTools(this); var typeMapper = new TypeMapper(code, ef, textTransform.Errors); var fileManager = EntityFrameworkTemplateFileManager.Create(this); var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) { return string.Empty; } WriteHeader(codeStringGenerator, fileManager); foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection)) { if(entity.Name.StartsWith("Sys") || entity.Name.StartsWith("JOB")) { fileManager.StartNewFile(entity.Name + "BLL.cs"); var simpleProperties = typeMapper.GetSimpleProperties(entity); #> using System; using System.Collections.Generic; using System.Linq; using Apps.Models; using Apps.Common; using Microsoft.Practices.Unity; using System.Transactions; using Apps.IBLL; using Apps.IDAL; using Apps.BLL.Core; using Apps.Locale; using Apps.Models<#=entity.Name.IndexOf("_")>0?"."+entity.Name.Substring(0,entity.Name.IndexOf("_")):".Sys" #>; namespace Apps.BLL { public partial class <#=entity.Name #>BLL: Virtual_<#=entity.Name #>BLL,I<#=entity.Name #>BLL { } <# EndNamespace(code); } } fileManager.Process(); #>
代码生成后以下,什么都没有实现继承接口,和上面的TT模版的类
namespace Apps.BLL { public partial class SysSampleBLL: Virtual_SysSampleBLL,ISysSampleBLL { } }
好吧,我只是想省掉写: Virtual_SysSampleBLL,ISysSampleBLL
OK,运行以后仍是熟悉的面孔,可是能够重载了,咱们重载一下,好处理咱们的业务!
新建SysSampleBLL.cs
namespace Apps.BLL { public partial class SysSampleBLL { public override bool Create(ref ValidationErrors errors, SysSampleModel model) { try { SysSample entity = m_Rep.GetById(model.Id); if (entity != null) { errors.Add(Resource.PrimaryRepeat); return false; } entity = new SysSample(); entity.Id = model.Id; entity.Name = model.Name.TrimStart(); entity.Age = model.Age; entity.Bir = model.Bir; entity.Photo = model.Photo; entity.Note = model.Note; entity.CreateTime = model.CreateTime; if (m_Rep.Create(entity)) { return true; } else { errors.Add(Resource.InsertFail); return false; } } catch (Exception ex) { errors.Add(ex.Message); ExceptionHander.WriteException(ex); return false; } } } }
一样的。咱们能够对Model层进行重构,相似BLL层。利用虚属性,能够对属性进行注解。来得到优先级,和一次生成编译经过
//------------------------------------------------------------------------------ // <auto-generated> // 此代码已从模板生成。 // // 手动更改此文件可能致使应用程序出现意外的行为。 // 若是从新生成代码,将覆盖对此文件的手动更改。 // </auto-generated> //------------------------------------------------------------------------------ using Apps.Models; using System; namespace Apps.Models.Sys { public class Virtual_SysSampleModel { public virtual string Id { get; set; } public virtual string Name { get; set; } public virtual Nullable<int> Age { get; set; } public virtual Nullable<System.DateTime> Bir { get; set; } public virtual string Photo { get; set; } public virtual string Note { get; set; } public virtual Nullable<System.DateTime> CreateTime { get; set; } } }
//------------------------------------------------------------------------------ // <auto-generated> // 此代码已从模板生成。 // // 手动更改此文件可能致使应用程序出现意外的行为。 // 若是从新生成代码,将覆盖对此文件的手动更改。 // </auto-generated> //------------------------------------------------------------------------------ using Apps.Models; using System; namespace Apps.Models.Sys { public partial class SysSampleModel:Virtual_SysSampleModel { } }
而后本身建Model对其重载
-------------------------------------------------------------------丑陋的分割线----------------------------------------------------------------------------------------
到此,咱们重构了DAL层和BLL层。对比原来的代码生成器方式。咱们新建一个表不用再生成DAL层和BLL层的代码。直达界面
利用代码生成器得到控制器和View视图。直接获得界面。一个字爽。你们能够下载代码来研究
代码生成器在第一节下载,可是代码生成器本人好久没有维护,可能生成的index.cshtml会有一些问题,可是好很好解决。本身花点时间来设计成本身的前端生成器。
OK、本文到此结束,谢谢