在前面隨筆,我介紹了整個ABP優化過框架的分層模型,包括儘可能簡化整個ABP框架的各個層的關係,以及歸入一些基類的輔助處理,使得咱們對應業務分層類或者接口儘量減小代碼,並具備生產環境所須要的基類接口,經過我對整個ABP框架模型的分析,咱們能夠結合代碼生成工具Database2Sharp來生成對應分層的代碼,該工具後臺具有數據庫表所須要的一切字段信息和關係信息,所以咱們肯定好邏輯關係就能夠生成對應分層的代碼。本篇隨筆介紹代碼生成工具Database2Sharp生成基於ABP框架的分層代碼過程。
1)ABP框架回顧
ABP框架主要仍是基於領域驅動的理念來構建整個架構的,其中領域驅動包含的概念有 域對象Entities、倉儲對象Repositories、域服務接口層Domain Services、域事件Domain Events、應用服務接口Application Services、數據傳輸對象DTOs等。
如下是ABP初始框架的各個分層的信息,它主要是分爲下面幾個項目分層。
Application應用層:應用層提供一些應用服務(Application Services)方法供展示層調用。一個應用服務方法接收一個DTO(數據傳輸對象)做爲輸入參數,使用這個輸入參數執行特定的領域層操做,並根據須要可返回另外一個DTO。
Core領域核心層,領域層就是業務層,是一個項目的核心,全部業務規則都應該在領域層實現。這個項目裏面,除了定義所需的領域實體類外,其實能夠定義咱們本身的自定義的倉儲對象(相似DAL/IDAL),以及定義本身的業務邏輯層(相似BLL/IBLL),以及基於AutoMapper映射規則等內容。
EntityFrameworkCore 實體框架核心層,這個項目不須要修改太多內容,只須要在DbContext裏面加入對應領域對象的倉儲對象便可。
Migrator數據遷移層,這個是一個輔助建立的控制檯程序項目,若是基於DB First,咱們能夠利用它來建立咱們項目的初始化數據庫。
Web.Core Web核心層,基於Web或者Web API的核心層,提供了對身份登錄驗證的基礎處理,沒有其餘內容。
Web.Core.Host Web API的宿主層,也是動態發佈Web API的核心內容,另外在Web API裏面整合了Swagger,使得咱們能夠方便對Web API的接口進行調試。
Tests 單元測試層,這個提供了一些應用層對象的模擬測試,其中測試的數據庫使用的是Entity Framework 的內存數據庫,不影響實際數據庫內容。
通過我進行簡化和優化處理的框架項目結構以下所示。
以上是VS裏面解決方案的項目結構,我根據項目之間的關係,整理了一個架構的圖形,以下所示。
上圖是以字典模塊爲介紹, 其中橘紅色的部分就是咱們爲各個分層須要根據數據庫構建對應的類或者接口文件。
例如對於01-Core模塊層,須要增長文件
對於03-Application.Common模塊來講,須要增長DTO和應用服務層接口文件
而對於04-Application應用層來講,須要增長對應的接口實現文件
而0五、0六、07模塊,咱們不須要加入任何文件,08-Caller層加入對WebAPI的遠程調用封裝類,給Winform、WPF/UWP、控制檯程序等調用。
一個模塊的變化,都會致使在上面各個分層之間增長對應的文件,這樣的架構肯定後,咱們就能夠根據對應的類生成規則進行生成接口。
2)利用代碼生成工具生成分層代碼
在前面隨筆《代碼生成工具Database2Sharp的架構介紹》中,我介紹了整個代碼生成工具的架構信息,所以咱們用代碼生成工具生成架構代碼的時候,能夠利用整個數據庫表的信息和關係信息來處理。
經過整合相關的生成規則,咱們能夠增長對應的ABP框架代碼的生成,以下代碼生成工具界面所示。
最終根據根據選擇數據庫表信息,一鍵生成相關ABP架構分層代碼,文件結構以下所示。
對比前面項目的介紹,咱們能夠看到各個分層的類代碼是徹底一致的。如對於領域層,包含了表名稱標記、字段信息和引用外鍵的對象。
複製代碼
/// <summary>
/// 通用字典明細項目信息,領域對象
/// </summary>
[Table("TB_DictData")]
public class DictData : FullAuditedEntity<string>
{
/// <summary>
/// 默認構造函數(須要初始化屬性的在此處理)
/// </summary>
public DictData()
{
}
#region Property Members
/// <summary>
/// 字典大類
/// </summary>
//[Required]
public virtual string DictType_ID { get; set; }
/// <summary>
/// 字典名稱
/// </summary>
//[Required]
public virtual string Name { get; set; }
/// <summary>
/// 字典值
/// </summary>
public virtual string Value { get; set; }
/// <summary>
/// 備註
/// </summary>
public virtual string Remark { get; set; }
/// <summary>
/// 排序
/// </summary>
public virtual string Seq { get; set; }
/// <summary>
/// 字典大類
/// </summary>
[ForeignKey("DictType_ID")]
public virtual DictType DictType { get; set; }
#endregion
}
複製代碼
對於DTO文件,咱們看看代碼信息
複製代碼
/// <summary>
/// 通用字典明細項目信息,DTO對象
/// </summary>
public class DictDataDto
{
/// <summary>
/// 默認構造函數(須要初始化屬性的在此處理)
/// </summary>
public DictDataDto()
{
}
#region Property Members
/// <summary>
/// 字典大類
/// </summary>
public virtual string DictType_ID { get; set; }
/// <summary>
/// 字典名稱
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 字典值
/// </summary>
//[Required]
public virtual string Value { get; set; }
/// <summary>
/// 備註
/// </summary>
public virtual string Remark { get; set; }
/// <summary>
/// 排序
/// </summary>
public virtual string Seq { get; set; }
#endregion
}
/// <summary>
/// 建立通用字典明細項目信息,DTO對象
/// </summary>
public class CreateDictDataDto : DictDataDto
{
}
/// <summary>
/// 用於根據條件分頁查詢,DTO對象
/// </summary>
public class DictDataPagedDto : PagedResultRequestDto
{
public DictDataPagedDto() { }
/// <summary>
/// 參數化構造函數
/// </summary>
/// <param name="skipCount">跳過的數量</param>
/// <param name="resultCount">最大結果集數量</param>
public DictDataPagedDto(int skipCount, int resultCount)
{
this.SkipCount = skipCount;
this.MaxResultCount = resultCount;
}
/// <summary>
/// 使用分頁信息進行初始化SkipCount 和 MaxResultCount
/// </summary>
/// <param name="pagerInfo">分頁信息</param>
public DictDataPagedDto(PagerInfo pagerInfo)
{
if (pagerInfo != null)
{
//默認設置
var pageSize = pagerInfo.PageSize > 0 ? pagerInfo.PageSize : 50;
var pageIndex = pagerInfo.CurrenetPageIndex > 0 ? pagerInfo.CurrenetPageIndex : 1;
this.SkipCount = pageSize * (pageIndex - 1);
this.MaxResultCount = pageSize;
}
}
#region Property Members
/// <summary>
/// 字典大類
/// </summary>
public virtual string DictType_ID { get; set; }
/// <summary>
/// 字典名稱
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// 字典值
/// </summary>
public virtual string Value { get; set; }
/// <summary>
/// 備註
/// </summary>
public virtual string Remark { get; set; }
/// <summary>
/// 排序
/// </summary>
public virtual string Seq { get; set; }
#endregion
}
複製代碼
DTO的映射文件代碼生成以下
複製代碼
/// <summary>
/// 通用字典明細項目信息,映射文件
/// </summary>
public class DictDataMapProfile : Profile
{
public DictDataMapProfile()
{
CreateMap<DictDataDto, DictData>();
CreateMap<DictData, DictDataDto>();
CreateMap<CreateDictDataDto, DictData>();
}
}
複製代碼
應用服務層接口實現代碼以下所示。
複製代碼
/// <summary>
/// 通用字典明細項目信息,應用層服務接口實現
/// </summary>
[AbpAuthorize]
public class DictDataAppService : MyAsyncServiceBase<DictData, DictDataDto, string, DictDataPagedDto, CreateDictDataDto, DictDataDto>, IDictDataAppService
{
private readonly IRepository<DictData, string> _repository;
public DictDataAppService(IRepository<DictData, string> repository) : base(repository)
{
_repository = repository;
}
/// <summary>
/// 自定義條件處理
/// </summary>
/// <param name="input">查詢條件Dto</param>
/// <returns></returns>
protected override IQueryable<DictData> CreateFilteredQuery(DictDataPagedDto input)
{
return base.CreateFilteredQuery(input)
.WhereIf(!DictType_ID.IsNullOrWhiteSpace(), t => t.DictType_ID.Contains(input.DictType_ID))
.WhereIf(!Name.IsNullOrWhiteSpace(), t => t.Name.Contains(input.Name))
.WhereIf(!Value.IsNullOrWhiteSpace(), t => t.Value.Contains(input.Value))
.WhereIf(!Remark.IsNullOrWhiteSpace(), t => t.Remark.Contains(input.Remark))
.WhereIf(!Seq.IsNullOrWhiteSpace(), t => t.Seq.Contains(input.Seq));
}
/// <summary>
/// 自定義排序處理
/// </summary>
/// <param name="query">可查詢LINQ</param>
/// <param name="input">查詢條件Dto</param>
/// <returns></returns>
protected override IQueryable<DictData> ApplySorting(IQueryable<DictData> query, DictDataPagedDto input)
{
return base.ApplySorting(query, input);
//示例代碼
//先按字典類型排序,而後同一個字典類型下的再按Seq排序
//return base.ApplySorting(query, input).OrderBy(s=>s.DictType_ID).ThenBy(s => s.Seq);
}
}
複製代碼
ApiCaller分層的代碼實現以下所示。
複製代碼
/// <summary>
/// 通用字典明細項目信息的Web API調用處理
/// </summary>
public class DictDataApiCaller : AsyncCrudApiCaller<DictDataDto, string, DictDataPagedDto, CreateDictDataDto, DictDataDto>, IDictDataAppService
{
/// <summary>
/// 提供單件對象使用
/// </summary>
public static DictDataApiCaller Instance
{
get
{
return Singleton<DictDataApiCaller>.Instance;
* 初始化圖數據須要的人員節點數據
*
* @param personBaseInfoRepository
* @return
*/
@Override
public void resetNeo4jPersonBaseInfoNode(PersonBaseInfoRepository personBaseInfoRepository) {
//查詢人員節點列表
List<PersonBaseInfo> personBaseInfos www.ztyLegw.cn= graphDataDao.queryPersonBaseInfo();數據庫
for (PersonBaseInfo personBaseInfo :personBaseInfos){
try {
personBaseInfoRepository.save(personBaseInfo);
}
catch (Throwable t){
//生成節點異常時,繼續跳過。
continue;
}
}
}
複製代碼
微信
初始化內部外部關心數據,代碼以下:架構
複製代碼
/********************************************開始初始化節點間關係的數據**********************************************/app
/**
* 初始化五大節點間的關係數據。
* @param neo4jRelationInfoRepository
* @return
*/
@Override
public void resetAllRelationInfo(Neo4jRelationInfoRepository neo4jRelationInfoRepository) {
long start = System.currentTimeMillis(www.tcgjgw.com);
//初始化人員-->工做關係,人員->學校;人員->論文;人員->住房信息4個主關係的數據。
List<Map<String,Object>>www.feironggw.cn lists = graphDataDao.queryEntityRelationInfo();
//計算內部關係信息 ,同事,校友,鄰居,合做者關係。
Map<String,List<String>> schoolFriendMap = new ConcurrentHashMap<>(); //校友框架
Map<String,List<String>> workTogetherMap = new ConcurrentHashMap<>(); //同事ide
Map<String,List<String>> neighborMap = new ConcurrentHashMap<>(); //鄰居
Map<String,List<String>> collaboratorMap = new ConcurrentHashMap<>();//論文合做者
for(Map<String,Object> map :lists){函數
String userId = "";
//獲取人員信息
if(StringUtils.isNoneEmpty((String)map.get("USERID")) && StringUtils.isNoneEmpty((String)map.get("USERNAME"))){
//取工做單位字段 UNIT_ID , UNIT_NAME
if(StringUtils.isNoneEmpty((String)map.get("UNIT_ID"www.wanhaoptdL.com)) && StringUtils.isNoneEmpty((String)map.get("UNIT_NAME"))){
//插入就任關係
neo4jRelationInfoRepository.generateGraphDataRelation_JZGX((String)map.get(www.yuntianyuL.cn"USERID"),(String)map.get("UNIT_ID"),(String)map.get("USERID")+"-www.yuntianyul.com>"+(String)map.get("UNIT_www.cmylli.com ID"));工具
//處理同事關係
if(workTogetherMap.containsKey((String)map.get("UNIT_ID"))){
List<String> list = workTogetherMap.get((String)map.get("UNIT_ID"));
if(!list.contains(www.cmyLgw.cn (String)map.get("USERID"))){
list.add((String)map.get("USERID"));
workTogetherMap.put((String)map.get("UNIT_ID"),list);
}
}else{
List<String> lis = new ArrayList<String>();
lis.add((String)map.get("USERID"));
workTogetherMap.put((String)map.get("UNIT_ID"),lis);
/// <summary>
/// 默認構造函數
/// </summary>
public DictDataApiCaller()
{
this.DomainName = "DictData";//指定域對象名稱,用於組裝接口地址
}
}
複製代碼
這些信息是根據數據庫對應字段信息和關係信息進行批量生成,咱們能夠在這基礎上進行必定的調整,以及增長本身的業務接口,那麼就很是方便了。
利用代碼生成工具的數據庫元數據,結合模板引擎NVelocity,咱們能夠爲咱們的項目框架代碼快速生成提供了一個快速有效、統一標準的生成方式,大大提升了生產效率。
主要研究技術:代碼生成工具、會員管理系統、客戶關係管理軟件、病人資料管理軟件、Visio二次開發、酒店管理系統、倉庫管理系統等共享軟件開發
專一於Winform開發框架/混合式開發框架、Web開發框架、Bootstrap開發框架、微信門戶開發框架的研究及應用。單元測試