上篇给大家从零开始搭建了一个我们的ASP.NET Core CMS系统的开发框架,具体为什么那样设计我也已经在第十篇文章中进行了说明。不过文章发布后很多人都说了这样的分层不是很合理,什么数据库实体应该跟仓储放在一起形成领域对象,什么ViewModel应该放在应用层结构仓储层与UI层。其实我想说的是,这样都没问题,看你自己的理解了!我上篇文章已经说了,如果你愿意,完全可以把所有的层融合在一起,随意合并分离这个依你个人喜好。我也是本着简单原则以及合适原则的思想来进行那样的分层结构,觉得这样层次更分明些。还有虽然现在DDD的思想很流行,但是实现起来确很复杂,小项目就别那样折腾了。如果你有不同的意见,欢迎加群讨论。什么?你问我群号?自己找去,我才不会告诉你!

本文已收录至《.NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划》作者:依乐祝原文地址:https://www.cnblogs.com/yilezhu/p/10112406.html

写在前面

今天我们就进入.NET Core实战项目之CMS的开发篇了,在开始之前呢我们首先需要把我们前面设计的逻辑模型转换成对应的物理模型,再根据我们物理模型生成相应的数据库脚本,接着我们就新建数据库,然后执行下我们生成的脚本即可。当然这么多表如果一个一个的写对应的数据库实体模型,一个一个的写仓储层代码以及服务层代码,感觉就是在搬砖啊,有木有,所以当然得自己实现个代码生成器来自动生成这些代码了!下面我们一步步来先生成下数据库然后再打造一个实体模型的代码生成器吧!

数据库生成

生成物理模型

  1. 首先用pdm打开我们设计的逻辑模型文件,后缀名是ldm的文件,如下图所示:

  2. 依次点击“Tools”-》"Generate Logical Data Model",如下图所示。或者直接使用快捷键Ctrl+Shift+P 打开物理模型生成选项对话框。

  3. 如下图所示选择号对应的数据库后,自定义物理模型的名称代码后点击确定即可生成物理模型。这里数据库类型有很多选择如:mysql,sqlserver,oracle等等,我们选择sqlserver2008,你可以随意从下拉框选择一个数据库进行生成(当然要跟你的数据库对应)!

  4. 注意这里生成的物理模型默认是不会生成注释的如下图所示:

    怎么办呢?如何才能讲Name 列的内容拷贝到Comment这个里面呢?因为这个Commment里面的内容才会真正的转换到数据库字段的注释。

    这时候你需要Tools->Execute Commands->Edit/Run Scripts (或者快捷键Ctrl+Shift+X)打开脚本执行的窗口,然后把下面的代码拷贝进行 run一下即可。

    '代码一:将Name中的字符COPY至Comment中
    
    Option   Explicit ValidationMode   =   True InteractiveMode   =   im_Batch
    
    Dim   mdl   '   the   current   model
    
    '   get   the   current   active   model Set   mdl   =   ActiveModel If   (mdl   Is   Nothing)   Then       MsgBox   "There   is   no   current   Model " ElseIf   Not   mdl.IsKindOf(PdPDM.cls_Model)   Then       MsgBox   "The   current   model   is   not   an   Physical   Data   model. " Else       ProcessFolder   mdl End   If
    
    '   This   routine   copy   name   into   comment   for   each   table,   each   column   and   each   view '   of   the   current   folder Private   sub   ProcessFolder(folder)       Dim   Tab   'running     table       for   each   Tab   in   folder.tables             if   not   tab.isShortcut   then                   tab.comment   =   tab.name                   Dim   col   '   running   column                   for   each   col   in   tab.columns                         col.comment=   col.name                   next             end   if       next
    
          Dim   view   'running   view       for   each   view   in   folder.Views             if   not   view.isShortcut   then                   view.comment   =   view.name             end   if       next
    
          '   go   into   the   sub-packages       Dim   f   '   running   folder       For   Each   f   In   folder.Packages             if   not   f.IsShortcut   then                   ProcessFolder   f             end   if       Next end   sub

    这里脚本执行的很快,你也可以把脚本保存起来下次再用,执行后的效果如下所示:

    我们的Comment这一行的内容已经跟Name一样了!

数据库脚本生成

  1. 首先打开我们生成的物理模型,扩展名为pdm的文件,如下图所示,乍一看跟物理模型差不多,实际上还是有区别的!

  2. 然后依次如下图所示选择“Database”->"Generate Database" 或者快捷键Ctrl+G打开数据库生成选项对话框

  3. 如下图所示设置一下生成的数据库脚本的路径以及脚本名称即可生成数据库脚本文件,如下图所示:

  4. 到我们上面设置的文件夹里即可查看到我们生成的数据库脚本,如下图所示:

数据库生成

  1. 打开我们的数据库,并新建一个名为CzarCms的新的数据库,如下图所示:

  2. 选择我们新建的数据库,然后按照如下图所示的方式打开我们刚才生成的数据库脚本

  3. 如下图所示确认一下目前选择的是你刚新建的数据库,然后点击执行,执行下脚本

  4. 不出以外的话会出现如下图所示的“命令已成功完成”的消息,这表示脚本执行成功了,然后刷新下我们刚才的数据库,可以看到我们的表已经生成成功了!

  5. 这里你可以检查下,看看生成的数据库表有没有问题,如果有问题的话,重新走一遍流程生成脚本然后执行下就行了,不过需要注意的是,如果你数据库中有数据就要当心了,重新生成的脚本会drop掉你的表重新创建,所以如果是个别字段出问题的话就逻辑模型以及物理模型修改后,手动在数据库中修改即可!

  6. 这里我给每个表的主键设计了自增,给isdelete等等设置了默认的0,以及addtime设置了getdate()等等。

实体模型生成器编写

好了,上面我已经带着你一步一步的演示了数据库的创建过程,下面我就带着你实现一个简单的POCO实体对象的代码生成器吧!什么?市面上不是有很多代码生成器吗?靠,我就是要带着你自己实现一个,咋滴?是用别人的爽,还是用自己实现的爽呢?自己琢磨吧!

思考

大家先脑补一下,如果是你想根据数据库实现一个代码生成器你的思路是怎样的呢?是不是首先得获取下数据库里面的所有的表,然后获取这些表对应的列以及列的类型,是否为空等等信息。然后再建一个模板,循环这些表的信息来根据模板创建对应的文件呢。至于模板文件可能你会想到T4或者CodeSmish模板等等,可这些都太复杂了,复杂的语法以及灵活性的问题我这里选择另一个文本文件的形式来进行代码的生成。

这个代码生成器的灵感以及部分代码来自于Zxw.Framework.NetCore,这个框架的github地址是:https://github.com/VictorTzeng/Zxw.Framework.NetCore/tree/master/Zxw.Framework.NetCore 有兴趣的小伙伴可以看下。

下面就让我们简单实现下我们自己的实体模型代码生成器吧.

实体代码生成器

  1. 首先我们创建一个Option对象来接收我们所需要的参数,比如说:数据库类型,数据库连接字符串,作者,实体模型的命名空间等等,如下所示:

     /// <summary>    /// yilezhu    /// 2018.12.12    /// 代码生成选项    /// </summary>    public class CodeGenerateOption    {        /// <summary>        /// 数据库连接字符串        /// </summary>        public string ConnectionString { get; set; }        /// <summary>        /// 数据库类型        /// </summary>        public string DbType  { get; set; }        /// <summary>        /// 作者        /// </summary>        public string Author { get; set; }
    
            /// <summary>        /// 代码生成时间        /// </summary>        public string GeneratorTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    
            /// <summary>        /// 输出路径        /// </summary>        public string OutputPath { get; set; }
    
            /// <summary>        /// 实体命名空间        /// </summary>        public string ModelsNamespace { get; set; }    }
  2. 从数据库里面获取所有表的脚本,这里我只是简单的实现了下SqlServer的代码,后续我会对这块进行提取封装,并支持MySql,Oracle,PSQL等等:

    //TODO 从数据库获取表列表以及生成实体对象            if (_options.DbType != DatabaseType.SqlServer.ToString())                throw new ArgumentNullException("这是我的错,目前只支持MSSQL数据库的代码生成!后续更新MySQL");            DatabaseType dbType = DatabaseType.SqlServer;            string strGetAllTables = @"SELECT DISTINCT d.name as TableName, f.value as TableCommentFROM      sys.syscolumns AS a LEFT OUTER JOIN                sys.systypes AS b ON a.xusertype = b.xusertype INNER JOIN                sys.sysobjects AS d ON a.id = d.id AND d.xtype = 'U' AND d.name <> 'dtproperties' LEFT OUTER JOIN                sys.syscomments AS e ON a.cdefault = e.id LEFT OUTER JOIN                sys.extended_properties AS g ON a.id = g.major_id AND a.colid = g.minor_id LEFT OUTER JOIN                sys.extended_properties AS f ON d.id = f.major_id AND f.minor_id = 0";            List<DbTable> tables = null;            using (var conn = new SqlConnection(_options.ConnectionString))            {                tables = conn.Query<DbTable>(strGetAllTables).ToList();
  3. 遍历每个表然后获取每个表对应的列(也是只实现的SqlServer的代码)

     tables.ForEach(item =>                {                    string strGetTableColumns = @"SELECT   a.name AS ColName, CONVERT(bit, (CASE WHEN COLUMNPROPERTY(a.id, a.name, 'IsIdentity')                 = 1 THEN 1 ELSE 0 END)) AS IsIdentity, CONVERT(bit, (CASE WHEN                    (SELECT   COUNT(*)                     FROM      sysobjects                     WHERE   (name IN                                         (SELECT   name                                          FROM      sysindexes                                          WHERE   (id = a.id) AND (indid IN                                                              (SELECT   indid                                                               FROM      sysindexkeys                                                               WHERE   (id = a.id) AND (colid IN                                                                                   (SELECT   colid                                                                                    FROM      syscolumns                                                                                    WHERE   (id = a.id) AND (name = a.name))))))) AND (xtype = 'PK'))                 > 0 THEN 1 ELSE 0 END)) AS IsPrimaryKey, b.name AS ColumnType, COLUMNPROPERTY(a.id, a.name, 'PRECISION')                 AS ColumnLength, CONVERT(bit, (CASE WHEN a.isnullable = 1 THEN 1 ELSE 0 END)) AS IsNullable, ISNULL(e.text, '')                 AS DefaultValue, ISNULL(g.value, ' ') AS CommentFROM      sys.syscolumns AS a LEFT OUTER JOIN                sys.systypes AS b ON a.xtype = b.xusertype INNER JOIN                sys.sysobjects AS d ON a.id = d.id AND d.xtype = 'U' AND d.name <> 'dtproperties' LEFT OUTER JOIN                sys.syscomments AS e ON a.cdefault = e.id LEFT OUTER JOIN                sys.extended_properties AS g ON a.id = g.major_id AND a.colid = g.minor_id LEFT OUTER JOIN                sys.extended_properties AS f ON d.id = f.class AND f.minor_id = 0WHERE   (b.name IS NOT NULL) AND (d.name = @TableName)ORDER BY a.id, a.colorder";                    item.Columns = conn.Query<DbTableColumn>(strGetTableColumns, new                    {                        TableName = item.TableName                    }).ToList();
  4. 接下来就是对数据库获取的列进行一个转换,根据数据库字段类型转换成对应的C#类型了

     item.Columns.ForEach(x =>                    {                        var csharpType = DbColumnTypeCollection.DbColumnDataTypes.FirstOrDefault(t =>                            t.DatabaseType == dbType && t.ColumnTypes.Split(',').Any(p =>                                p.Trim().Equals(x.ColumnType, StringComparison.OrdinalIgnoreCase)))?.CSharpType;                        if (string.IsNullOrEmpty(csharpType))                        {                            throw new SqlTypeException($"未从字典中找到\"{x.ColumnType}\"对应的C#数据类型,请更新DbColumnTypeCollection类型映射字典。");                        }
    
                            x.CSharpType = csharpType;                    });
  5. 既然所有的表以及表对应的列我们都拿到了,那么我们就可以进行代码的生成了,当然在生成之前还得创建我们的模板文件:

    // 本代码由代码生成器生成请勿随意改动// 生成时间  {GeneratorTime}using System;
    
    namespace {ModelsNamespace}{    /// <summary>    /// {Author}    /// {GeneratorTime}    /// {Comment}    /// </summary>    public class {ModelName}    {        {ModelProperties}    }}

    看到没有,很简单的POCO对象的样子,接下来就是生成对应的模板了,具体怎么生成呢?思考下:是不是首先读取模板文件到一个string里面,然后就是简单的replace了!很简单吧,具体的代码我都上传到了Github上,文章末尾我会给出地址。另外为了大家引用的方便我已经把这个Czar.Cms.Core项目制作成了Nuget包,大家只需要搜索这个包引用下就可以用了!什么?Nuget包怎么引用啊?骚年你可以上天了~

测试实体代码生成器

  1. Czar.Cms.Test 这个项目添加Nuget包引用,引用后的Nuget如下所示:

  2. 接下来就是新建一个测试类,然后创建一个依赖注入容器,并把我们需要的Option传递进去,如下所示:

     /// <summary>        /// 构造依赖注入容器,然后传入参数        /// </summary>        /// <returns></returns>        public IServiceProvider BuildServiceForSqlServer()        {            var services = new ServiceCollection();
    
                services.Configure<CodeGenerateOption>(options =>            {                options.ConnectionString = "Data Source=.;Initial Catalog=CzarCms;User ID=sa;Password=1;Persist Security Info=True;Max Pool Size=50;Min Pool Size=0;Connection Lifetime=300;";//这个必须                options.DbType = DatabaseType.SqlServer.ToString();//数据库类型是SqlServer,其他数据类型参照枚举DatabaseType//这个也必须                options.Author = "yilezhu";//作者名称,随你,不写为空                options.OutputPath = @"E:\workspace\vs2017\Czar.Cms\src\Czar.Cms.Models";//实体模型输出路径,为空则默认为当前程序运行的路径                options.ModelsNamespace = "Czar.Cms.Models";//实体命名空间            });            services.AddSingleton<CodeGenerator>();//注入Model代码生成器            return services.BuildServiceProvider(); //构建服务提供程序        }
  3. 接着就是写我们的测试方法了,代码如下:

     [Fact]        public void GeneratorModelForSqlServer()        {            var serviceProvider= BuildServiceForSqlServer();            var codeGenerator = serviceProvider.GetRequiredService<CodeGenerator>();            codeGenerator.GenerateModelCodesFromDatabase();            Assert.Equal(0,0);
    
            }
  4. 运行一下我们的Live Unit Testing 然后看一下我们的Czar.Cms.Models下面已经生成了对应的实体文件,如下图所示:

  5. 随便打开一个看小效果如下:我标注的你猜猜看都是对应的哪个Options

开源地址

这个系列教程的源码我会开放在GitHub以及码云上,有兴趣的朋友可以下载查看!觉得不错的欢迎StarGitHub:https://github.com/yilezhu/Czar.Cms码云:https://gitee.com/yilezhu/Czar.Cms如果你觉得这个系列对您有所帮助的话,欢迎以各种方式进行赞助,当然给个Star支持下也是可以滴!另外一种最简单粗暴的方式就是下面这种直接关注我们的公众号了:第一时间收到更新推送。

总结

这篇文章我们一步一步的生成了我们的数据库,然后手把手带着你实现了我们自己的实体模型代码生成器来简化我们的开发过程。接下来我们就开始实现仓储层应用层的代码了,同时我们会提取通用部分的代码来进行模板代码生成来简化我们的工作!俗话说的好,不会偷懒的程序员不是一个好爸爸,好丈夫,好儿子,减少代码的时间多抽点时间陪陪家人吧!如果你有其他想法可以在下方留言,或者加群跟大伙一起讨论。共同进步!共勉!

原文

相关文章:

  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

  • .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了

  • .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

  • .NET Core实战项目之CMS 第四章 入门篇-Git的快速入门及实战演练

  • .NET Core实战项目之CMS 第五章 入门篇-Dapper的快速入门看这篇就够了

  • .NET Core实战项目之CMS 第六章 入门篇-Vue的快速入门及其使用

  • .NET Core实战项目之CMS 第七章 设计篇-用户权限极简设计全过程

  • .NET Core实战项目之CMS 第八章 设计篇-内容管理极简设计全过程

  • .NET Core实战项目之CMS 第九章 设计篇-白话架构设计

  • .NET Core实战项目之CMS 第十章 设计篇-系统开发框架设计

原文地址:https://www.cnblogs.com/yilezhu/p/10112406.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

.NET Core实战项目之CMS 第十一章 开发篇-数据库生成及实体代码生成器开发相关推荐

  1. .NET Core实战项目之CMS 第七章 设计篇-用户权限极简设计全过程

    写在前面 这篇我们对用户权限进行极简设计并保留其扩展性.首先很感谢大家的阅读,前面六章我带着大家快速入门了ASP.NET Core.ASP.NET Core的启动过程源码解析及配置文件的加载过程源码解 ...

  2. .NET Core实战项目之CMS 第六章 入门篇-Vue的快速入门及其使用

    写在前面 上面文章我给大家介绍了Dapper这个ORM框架的简单使用,大伙会用了嘛!本来今天这篇文章是要讲Vue的快速入门的,原因是想在后面的文章中使用Vue进行这个CMS系统的后台管理界面的实现.但 ...

  3. .NET Core实战项目之CMS 第五章 入门篇-Dapper的快速入门看这篇就够了

    写在前面 上篇文章我们讲了如在在实际项目开发中使用Git来进行代码的版本控制,当然介绍的都是比较常用的功能.今天我再带着大家一起熟悉下一个ORM框架Dapper,实例代码的演示编写完成后我会通过Git ...

  4. .NET Core实战项目之CMS 第四章 入门篇-Git的快速入门及实战演练

    写在前面 上篇文章.NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入我带着大家通过分析了一遍ASP.NET Core的源码了解了它的启动过程,然后又带着大家熟悉了一遍配置文 ...

  5. .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

    写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着带着你一步一步的配置了.NET Core的开发环境并创建了一个ASP.NET Core的mvc项目,同时又通过一个实战 ...

  6. .NET Core实战项目之CMS 第十七章 CMS网站系统的部署

    目前我们的.NET Core实战项目之CMS系列教程基本走到尾声了,通过这一系列的学习你应该能够轻松应对.NET Core的日常开发了!当然这个CMS系统的一些逻辑处理还需要优化,如没有引入日志组件以 ...

  7. .NET Core实战项目之CMS 第十三章 开发篇-在MVC项目结构介绍及应用第三方UI

    作为后端开发的我来说,前端表示真心玩不转,你如果让我微调一个位置的样式的话还行,但是让我写一个很漂亮的后台的话,真心做不到,所以我一般会选择套用一些开源UI模板来进行系统UI的设计.那如何套用呢?今天 ...

  8. .NET Core实战项目之CMS 第十六章 用户登录及验证码功能实现

    前面为了方便我们只是简单实现了基本业务功能的增删改查,但是登录功能还没有实现,而登录又是系统所必须的,得益于 ASP.NET Core的可扩展性因此我们很容易实现我们的登录功能.今天我将带着大家一起来 ...

  9. .NET Core实战项目之CMS 第十五章 各层联动工作实现增删改查业务

    连着两天更新叙述性的文章大家可别以为我转行了!哈哈!今天就继续讲讲我们的.NET Core实战项目之CMS系统的教程吧!这个系列教程拖得太久了,所以今天我就以菜单部分的增删改查为例来讲述下我的项目分层 ...

最新文章

  1. 【转】初等数论 ——原根、指标及其应用
  2. 【原创视频教程】学生信息管理系统6--学员信息管理(完结篇)
  3. 汇编 CALL和RET指令
  4. 运行iDT算法代码及后续特征编码
  5. 中间件及tomcat的内存溢出调优
  6. 使用PHP+Redis实现延迟任务,实现自动取消订单功能
  7. 点击Cell中的按钮时,如何取所在的Cell
  8. vue.js 编程导航,如何传递参数?
  9. 动态规划之神奇的口袋问题
  10. 让计算机启动更快的十五招
  11. 如果人生只剩最后一天,你想在这天干什么?
  12. 【webi 专题】能否通过传参数动态生成二维图表?
  13. EF Code First学习笔记 初识Code First
  14. SQLPlus登录及使用
  15. 想撤回没门!电脑版微信、QQ 、TIM的防撤回工具
  16. GAN(生成对抗网络)的系统全面介绍(醍醐灌顶)
  17. kafka彻底删除topic清理数据
  18. Vivado IP核fifo使用指南
  19. html5 邮箱后缀自动填写,JS输入用户名自动显示邮箱后缀列表的方法
  20. DevOps ACA 阿里云效软件测试和质量保证(八)

热门文章

  1. highcharts 怎么去掉鼠标悬停效果_练瑜伽减肥没效果什么原因?
  2. vcenter 6.7 (vcsa)部署指南
  3. JavaScript校验网址
  4. 网构软件-Internetware
  5. centos 新建swap区文件
  6. mysql导入sql脚本命令
  7. Oracle数据库-主键(primary key)、外键(foreign key)、候选键(candidate key)、超键(super key)和references总结...
  8. CSS text-indent 属性
  9. TI-89T 教你在C程序里调用TI-BASIC程序,看看是否有人对这个感兴趣
  10. 微软翻译api的使用介绍和注意事项