小程序大智慧,sqlserver 注释提取工具

原文:小程序大智慧,sqlserver 注释提取工具

开篇背景

我习惯在写表的创建脚本时将注释直接写在脚本里,比如

/*账套*/
CREATE TABLE [dbo].[AccountingBook]
(
	[IDNO]			NVARCHAR (255) NOT NULL,	/*ID*/
    [BH]			NVARCHAR (255) NULL,		/*业务编号*/
	[Name]			NVARCHAR (255) NOT NULL,	/*名称*/
	[Decription]	NVARCHAR (255) NULL,		/*描述*/
	[Owner]			NVARCHAR (255) NOT NULL,	/*所属*/
	CONSTRAINT [PK_AccountingBook] PRIMARY KEY CLUSTERED ([IDNO] ASC)
)

这样写很直观,如果在vs里创建一个数据库项目,把表的创建脚本放在里面进行管理,就非常方便的。

由于习惯用自己的Orm框架,所以DTO也就是那些数据映射实体我都是用codeSmith生成,生成这些DTO对象时,我想共用我的那些注释,那么我该怎么办呢,之前,我需要把这些注释复制出来写成一些注释创建的脚本,像这样  

exec sp_addextendedproperty N'MS_Description', N'字段描述', N'user', N'dbo', N'table', N'表名', N'column', N'字段名'

添加注释的目的是除了在使用数据库连接工具时方便查看表和字段的说明外,还可以使用CodeSmith生成代码的时候就可以通过编写模版生成带注释的映射DTO 对象,如下  

/// <summary>
/// 业务编号
/// </summary>
[Column(ColumnName=Columns.BH,FullName=Columns.BHFullName,Index=1,CType=typeof(string),Description="业务编号")]
[DataMember(Order = 1)]
public virtual string BH{get;set;}

但是由于表创建脚本里的注释不能直接写入到数据库的表和字段中,所以注释的创建脚本我需要再写一次,我觉得比较不爽,于是我决定写个小工具从表的创建脚本里面抽取那些本来就写好的注释,从而减小重复机械的工作,也防止错误的发生。

这样一个程序非常简单,下面说一下思路

实现

一,写好带注释的表脚本,并提取这些信息

格式按文章开始讲到的那样写好,即"/*注释*/",“*”可以是多个,比如"/*********注释***********/",并将这些脚本存放到相同根目录

要提取这些注释,最大的功臣非正则表达式莫属了

    

a.提取表头的注释,也就是表名的解释正则表达式      

 private readonly Regex _tableReg = new Regex(@"/[\*]+([^\*]*)[\*]+/[\r\n\s]*CREATE TABLE \[dbo\].\[(\w*)\]");

b.提取列的注释正则表达式

private readonly Regex _columnsReg = new Regex(@"\[([\w]*)\][^\/]*/[\*]+([^\*]*)[\*]+/");

二,递归查找到这些表的创建脚本,将每个生成注释脚本的字符串连接起来

Func<string, List<string>> getFolderSqlNotes = null;
    getFolderSqlNotes = path =>
    {
        var listAll = new List<string>();
        var files = Directory.GetFiles(path);
        var dirs = Directory.GetDirectories(path);
        foreach (string t in dirs)
        {
            listAll.AddRange(getFolderSqlNotes(t)); ;
        }
        var listStr = files.Where(m => m.EndsWith(".sql")).Select(GetDescriptionSql).ToList();
        listAll.AddRange(listStr);
        return listAll;
    };
    var list = getFolderSqlNotes(Path);
    return string.Join("\r\n", list);

三,执行生成好的脚本(如下图),注释创建完成

四,用codesimth 生成映射类(已带注释)

核心代码

 1 namespace GenrerateSqlDescription
 2 {
 3     using System;
 4     using System.Collections.Generic;
 5     using System.IO;
 6     using System.Linq;
 7     using System.Text;
 8     using System.Text.RegularExpressions;
 9
10
11     public class SqlNotesGenerator
12     {
13         private readonly Regex _tableReg = new Regex(@"/[\*]+([^\*]*)[\*]+/[\r\n\s]*CREATE TABLE \[dbo\].\[(\w*)\]");
14         private readonly Regex _columnsReg = new Regex(@"\[([\w]*)\][^\/]*/[\*]+([^\*]*)[\*]+/");
15         private const string TableDescriptionCrateSqlFormat = "EXEC sp_addextendedproperty 'MS_Description','{0}','user ',dbo,'table',[{1}];\r\n";
16         private const string ColumnDescriptionCrateSqlFormat = "EXEC sp_addextendedproperty 'MS_Description','{0}','user',dbo,'table',[{1}],'column','{2}';\r\n";
17         private const string TableDescriptionDropSqlFormat = "EXEC sp_dropextendedproperty 'MS_Description','user',dbo,'table',[{0}];\r\n";
18         private const string ColumnescriptionDropSqlFormat = "EXEC sp_dropextendedproperty 'MS_Description','user',dbo,'table',[{0}],'column','{1}';\r\n";
19         private const string CheckTableExistsSqlFormat = "IF OBJECT_ID(N'{0}',N'U') IS NOT NULL \r\nBEGIN \r\n";
20         private const string EndStr = "END";
21         private const string Tab = "    ";
22
23         public bool GenDrop { get; set; }
24         public string Path { get; set; }
25
26         private string GetDescriptionSql(string path)
27         {
28             var sb = new StringBuilder();
29             var fs = File.OpenRead(path);
30             var fileRd = new StreamReader(fs);
31             var str = fileRd.ReadToEnd();
32             var tableMatch = _tableReg.Match(str);
33             if (tableMatch.Length < 2) return string.Empty;
34
35             var tableName = tableMatch.Groups[2].Value;
36             var tableDes = tableMatch.Groups[1].Value;
37             if (string.IsNullOrEmpty(tableName) || string.IsNullOrEmpty(tableDes)) return string.Empty;
38
39             var columnStr = str.Substring(str.IndexOf("(", StringComparison.Ordinal));
40             var matches = _columnsReg.Matches(columnStr);
41
42             sb.AppendFormat(CheckTableExistsSqlFormat, tableName);
43
44             sb.Append(Tab);
45             if (GenDrop)
46                 sb.AppendFormat(TableDescriptionDropSqlFormat, tableName);
47             else
48                 sb.AppendFormat(TableDescriptionCrateSqlFormat, tableDes, tableName);
49             foreach (Match match in matches)
50             {
51                 var columnName = match.Groups[1].Value;
52                 var description = match.Groups[2].Value;
53                 if (string.IsNullOrEmpty(columnName) || string.IsNullOrEmpty(description))
54                     continue;
55                 sb.Append(Tab);
56                 if (GenDrop)
57                     sb.AppendFormat(ColumnescriptionDropSqlFormat, tableName, columnName);
58                 else
59                     sb.AppendFormat(ColumnDescriptionCrateSqlFormat, description, tableName, columnName);
60             }
61
62             sb.AppendLine(EndStr);
63             return sb.ToString();
64         }
65
66
67         public string GetGenerateSql()
68         {
69             Func<string, List<string>> getFolderSqlNotes = null;
70             getFolderSqlNotes = path =>
71             {
72                 var listAll = new List<string>();
73                 var files = Directory.GetFiles(path);
74                 var dirs = Directory.GetDirectories(path);
75                 foreach (string t in dirs)
76                 {
77                     listAll.AddRange(getFolderSqlNotes(t)); ;
78                 }
79                 var listStr = files.Where(m => m.EndsWith(".sql")).Select(GetDescriptionSql).ToList();
80                 listAll.AddRange(listStr);
81                 return listAll;
82             };
83             var list = getFolderSqlNotes(Path);
84             return string.Join("\r\n", list);
85         }
86
87     }
88
89 }

SqlNotesGenerator

CodeSimith模版

  1 <%--
  2 Name:
  3 Author:
  4 Description:
  5 --%>
  6 <%@ CodeTemplate Language="C#" TargetLanguage="C#" Src="" Inherits="OutputFileCodeTemplate" Debug="False" Description="Template description here." %>
  7 <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema"  Category="Context"  Optional="True" Description="the table name"   %>
  8 <%@ Assembly Name="SchemaExplorer" %>
  9 <%@ Import Namespace="SchemaExplorer" %>
 10 <%@ Assembly Name="CodeSmith.BaseTemplates" %>
 11 <%@ Import Namespace="CodeSmith.BaseTemplates" %>
 12 <%@ Assembly Name="CodeSmith.CustomProperties" %>
 13 <%@ Import Namespace="CodeSmith.CustomProperties" %>
 14 //------------------------------------------------------------------------------
 15 // <auto-generated>
 16 //     This code generated by the tool, do not propose to amend
 17 //       Generation time:<%=DateTime.Now%>
 18 // </auto-generated>
 19 //------------------------------------------------------------------------------
 20 using System;
 21 using System.Data;
 22 using System.Runtime.Serialization;
 23 using XDbFramework;
 24 using BPM_M01.DataAccessLayer.Base;
 25 using System.Xml.Serialization;
 26 using System.Diagnostics;
 27 using System.CodeDom.Compiler;
 28
 29 namespace <%=Namespace%>
 30 {
 31     [Table(TableName = <%=this.SourceTable.Name%>.Table.Name ,Descripton = "<%=this.SourceTable.Description%>",GenreratePK = <%=GenreratePK.ToString().ToLower()%>)]
 32       [GeneratedCodeAttribute("System.Xml", "2.0.50727.4927")]
 33     [DebuggerStepThroughAttribute()]
 34     public partial class <%=this.SourceTable.Name%> : DtoBase
 35     {
 36         public static class Table
 37         {
 38             public const string Name = "<%=this.SourceTable.Name%>";
 39         }
 40         public static class Columns
 41         {
 42         <%for(int i=0; i<this.SourceTable.Columns.Count;i++)
 43         {
 44             string colName=this.SourceTable.Columns[i].Name;%>
 45             public const string <%=colName%> = "<%=colName%>";
 46             public const string <%=colName%>FullName =Table.Name + "." + "<%=colName%>";
 47         <%}%>
 48         }
 49
 50     <%for(int i=0; i<this.SourceTable.Columns.Count;i++)
 51     {
 52         int namelength=this.SourceTable.Columns[i].Name.Length;
 53         string colName=this.SourceTable.Columns[i].Name;
 54         if(colName == "ID" || colName == "IDNO") continue;
 55         string titleCaseColumName = colName.Substring(0,1).ToUpper() + colName.Substring(1,colName.Length-1);
 56         %>
 57
 58         /// <summary>
 59         /// <%=this.SourceTable.Columns[i].Description%>
 60         /// </summary>
 61         <%if(this.SourceTable.Columns[i].IsPrimaryKeyMember){%>
 62         [Column(KeyType = KeyTypeEnum.PrimaryKey,FullName="<%=this.SourceTable.Name%>.<%=this.SourceTable.Columns[i].Name%>", ColumnName="<%=this.SourceTable.Columns[i].Name%>",Index=<%=i%>,Description="<%=this.SourceTable.Columns[i].Description%>")]
 63         <%}%>
 64         <%else{%>
 65         <%if(this.SourceTable.Columns[i].IsForeignKeyMember)%>
 66         <%//
 67         foreach(TableKeySchema tks in SourceTable.ForeignKeys)
 68         {
 69         //
 70
 71             foreach(MemberColumnSchema mcs in tks.ForeignKeyMemberColumns)
 72             {
 73
 74                 //
 75                 if(mcs.Name == SourceTable.Columns[i].Name)
 76                 {
 77                     TableSchema ts= tks.PrimaryKeyTable;%>
 78         [Column(ColumnName=Columns.<%=colName%>,KeyType = KeyTypeEnum.ForeignKey,FullName=Columns.<%=colName%>FullName,CType=typeof(<%=GetCSharpVariableType(this.SourceTable.Columns[i])%>),ForeignKeyTableName="<%=ts.Name%>",ForeignKeyFiledName="<%=ts.PrimaryKey.MemberColumns[0].Name%>", DbType=<%=GetSqlDBType(this.SourceTable.Columns[i].NativeType)%> Index=<%=i%>,Description="<%=this.SourceTable.Columns[i].Description%>")]
 79                    <% break;
 80                 }
 81             }
 82         }
 83         %>
 84         <%else{%>
 85         [Column(ColumnName=Columns.<%=colName%>,FullName=Columns.<%=colName%>FullName,Index=<%=i%>,CType=typeof(<%=GetCSharpVariableType(this.SourceTable.Columns[i])%>),Description="<%=this.SourceTable.Columns[i].Description%>")]
 86         <%}%>
 87         <%}%>
 88         [DataMember(Order = <%=i%>)]
 89         public virtual <%=GetCSharpVariableType(this.SourceTable.Columns[i])%> <%=titleCaseColumName%>{get;set;}
 90
 91     <%}%>
 92     }
 93 }
 94
 95 <script runat="template">
 96 // Override the OutputFile property and assign our specific settings to it.
 97 [FileDialog(FileDialogType.Save, Title="Select Output File", Filter="C# Files (*.cs)|*.cs", DefaultExtension=".cs")]
 98 public override string OutputFile
 99 {
100     get {return base.OutputFile;}
101     set {base.OutputFile = value;}
102 }
103 private string _Namespace;
104 public string Namespace
105 {
106     get{return _Namespace;}
107     set{_Namespace = value;}
108 }
109
110 public bool GenreratePK{get;set;}
111 </script>
112 <script runat="template">
113 public string GetSqlDBType(string type)
114 {
115     switch(type)
116     {
117         case "int": return "SqlDbType.Int,";
118         case "bit": return "SqlDbType.Bit,";
119         case "bigint": return "SqlDbType.BigInt,";
120         case "tinyint": return "SqlDbType.TinyInt,";
121         case "nvarchar": return "SqlDbType.NVarChar,";
122         case "date": return "SqlDbType.Date,";
123         case "datetime": return "SqlDbType.DateTime,";
124         case "char": return "SqlDbType.Char,";
125         case "decimal": return "SqlDbType.Decimal,";
126         case "float": return "SqlDbType.Float,";
127         case "image": return "SqlDbType.Image,";
128         case "money": return "SqlDbType.Money,";
129         case "nchar": return "SqlDbType.NChar,";
130         case "ntext": return "SqlDbType.NText,";
131         case "real": return "SqlDbType.Real,";
132         case "smalldatetime": return "SqlDbType.SmallDateTime,";
133         case "smallint": return "SqlDbType.SmallInt,";
134         case "smallmoney": return "SqlDbType.SmallMoney,";
135         case "text": return "SqlDbType.Text,";
136         case "timestamp": return "SqlDbType.Timestamp,";
137         case "udt": return "SqlDbType.Udt,";
138         case "uniqueidentifier": return "SqlDbType.UniqueIdentifier,";
139         case "varbinary": return "SqlDbType.VarBinary,";
140         case "varchar": return "SqlDbType.VarChar,";
141         case "variant": return "SqlDbType.Variant,";
142         case "xml": return "SqlDbType.Xml,";
143         default : return "";
144     }
145
146 }
147 public string GetCSharpVariableType(ColumnSchema column)
148 {
149     switch (column.DataType)
150     {
151         case DbType.AnsiString: return "string";
152         case DbType.AnsiStringFixedLength: return "string";
153         case DbType.Binary: return "byte[]";
154         case DbType.Boolean: return "bool?";
155         case DbType.Byte: return "byte";
156         case DbType.Currency: return "decimal?";
157         case DbType.Date: return "DateTime?";
158         case DbType.DateTime: return "DateTime?";
159         case DbType.Decimal: return "decimal?";
160         case DbType.Double: return "double?";
161         case DbType.Guid: return "Guid";
162         case DbType.Int16: return "short?";
163         case DbType.Int32: return "int?";
164         case DbType.Int64: return "long?";
165         case DbType.Object: return "object";
166         case DbType.SByte: return "sbyte";
167         case DbType.Single: return "float?";
168         case DbType.String: return "string";
169         case DbType.StringFixedLength: return "string";
170         case DbType.Time: return "TimeSpan";
171         case DbType.UInt16: return "ushort?";
172         case DbType.UInt32: return "uint?";
173         case DbType.UInt64: return "ulong?";
174         case DbType.VarNumeric: return "decimal?";
175         default:
176         {
177             return "__UNKNOWN__" + column.NativeType;
178         }
179     }
180 }
181 </script>

代码

下载

GenrerateSqlDescription_8_28.zip  

时间: 2024-09-28 08:38:19

小程序大智慧,sqlserver 注释提取工具的相关文章

微信小程序(微信应用号)开发工具0.9版安装详细教程_其它综合

微信小程序全称微信公众平台·小程序,原名微信公众平台·应用号(简称微信应用号) 声明 •微信小程序开发工具类似于一个轻量级的IDE集成开发环境,目前仅开放给了少部分受微信官方邀请的人士(据说仅200个名额)进行内测,因此目前未受到邀请的人士只能使用破解版: •本破解版资源来自于网上,与本人无关,仅供技术开发人员研究之用: •由于尚属内测阶段,因此迭代更新非常快,后续很可能由于升级而导致暂时无法使用. 特别注意 •由于目前发布的0.9版本必须验证才能登录(估计是为了验证是否为内测人士),因此必须先

微信小程序购物商城系统开发系列-工具篇的介绍_javascript技巧

微信小程序开放公测以来,一夜之间在各种技术社区中就火起来啦.对于它 估计大家都不陌生了,对于它未来的价值就不再赘述,简单一句话:可以把小程序简单理解为一个新的操作系统.新的生态,未来大部分应用场景都将给予微信小程序进行研发.基于对它的敬畏以及便于大家快速上手,特整理微信小程序商城开发系列,未来将持续增加微信小程序技术文章,让大家可全面了解如何快速开发微信小程序商城. 本篇文章主要介绍微信小程序官方提供的开发工具,俗话说:欲工善其身,必先利其器. 小程序开发文档地址https://mp.weixi

小程序开发工具全新上线 附下载地址和教程

"为了让开发者更高效地开发和发布小程序,微信开发者工具全新改版上线,并新增测试系统.腾讯云工具.运维性能监控.小程序分阶段发布.WXS脚本语言等" 01.微信开发者工具 为提升小程序开发体验,帮助开发者更高效地开发小程序代码,微信开发者工具全新改版,现面向所有开发者开放. A 新增 申请测试报告功能.为了方便广大开发者检测小程序程序缺陷.评估小程序产品质量,小程序提供了免费的云真机测试环境以及一整套测试方案.在小程序交付到真实用户手中使用之前,你可以将小程序分发到我们的云平台以模拟用户

微信小程序架构分析 (上)

[引自第九程序的博客]相信不少上手试用了微信小程序开发者工具的开发者都会对其实现有些疑惑, 本文试图对其架构模型进行一些解析.如有错误之处,欢迎留言指出. 本文分为以下几个部分: 小程序调试技巧 小程序主要模块构成 小程序模块间通信 设计理念分析 小程序调试技巧 微信开发者工具默认禁用了右键打开调试面板功能,我们可以修改开发者工具部分代码移除该限制. 找到 app.nw 项目根目录,Mac 下为/Applications/wechatwebdevtools.app/Contents/Resour

史诗手册!微信小程序新手自学入门宝典!你想要的都在这里

一.小程序官方指南 1:官方开发工具下载: https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=201714 0.12.1304Win版:https://pan.baidu.com/s/1miNleBY 0.12.1304Mac版:https://pan.baidu.com/s/1qYNIQZy 2:官方提供的简单教程 https://mp.weixin.qq.com/debug/wxadoc/dev/ 3:小程序

移动开发之【微信小程序】的原理与权限问题以及相关的简易教程

这几天圈子里到处都在传播着这样一个东西,微信公众平台提供了一种新的开放能力,开发者可以快速开发一个小程序,取名曰:微信公众平台-小程序 据说取代移动开发安卓和苹果,那这个东东究竟是干吗用的?但很多人觉得是网页版应用. 有的人很鸡冻,但是--最后文章会提及具体的权限开放问题,所以,还是保持一颗冷静的比较好. 那我们先来看看组件和API开放了哪些服务: 视图容器:视图(View).滚动视图.Swiper 基础内容:图标.文本.进度条 表单组件:按钮.表单等等 操作反馈 导航 媒体组建:音频.图片.视

半年过去,小程序的冰火真相

本文讲的是半年过去,小程序的冰火真相,7 月底开始,小程序第三方服务商火速移动创始人赵九州被微信近来的节奏搞得兴奋又紧张. 赵九州发现,从 6.7 月份开始,「微信基本上每两三天就会放出一波新功能.」而仅在 7 月 25 日到 8 月 5 日 10 天内,小程序又分四次开放了社交立减金.群小程序入口.支持门店小程序跳转关联以及最多关联 50 个公众号等能力. 微信的步伐变得更加激进,但这份「疯狂」似乎再没有引起巨大的波澜,和赵九州一样感到兴奋的人却好像消失在了主流视野里.可在半年甚至更久之前,光

微信公众平台小程序开发教程

​ 本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果.这个小程序的首页将会显示欢迎语以及当前用户的微信头像,点击头像,可以在新开的页面中查看当前小程序的启动日志.下载源码 1. 获取微信小程序的 AppID 如果你是收邀请的开发者,我们会提供一个帐号,利用提供的帐号,登录 https://mp.weixin.qq.com ,就可以在网站的"设置"-"开发者设置"中,查看到微信小程序的 AppID 了,注意不可直接使用服务号或订阅号的 A

微信小程序开发入门教程

在这篇微信小程序开发教程中,我们将向你介绍快速试用和体验微信小程序开发工具和官方示例Demo. 本系列教程将引导你完成如下任务: 下载微信web开发者工具和小程序官方Demo. 添加小程序示例Demo到项目 体验小程序常用组件及接口   第一部分 下载开发者工具和官方Demo   微信小程序开发者工具 为了帮助开发者简单和高效地开发微信小程序,微信官方推出了全新的微信小程序开发者工具,该工具集成了开发调试.代码编辑及程序发布等功能. 下载地址为  windows 64 . windows 32